Android 中 TCP 协议的实战运用

在 Android 开发中,网络通信是核心功能之一。TCP 作为可靠的传输层协议,被广泛应用于需要稳定数据传输的场景 —— 如即时通讯、文件上传、智能家居控制等。与 HTTP 的 “请求 - 响应” 模式不同,TCP 的 “长连接” 特性使其能实现实时双向通信,但也带来了连接管理、断线重连、数据粘包等特有挑战。

本文将从 Android 开发视角,系统讲解 TCP 协议的核心原理、在 Android 中的实现方式,以及实战中的关键问题(如主线程规避、断线重连、数据解析),并提供可直接复用的代码框架。

一、TCP 协议基础:为什么需要它?

在深入代码之前,先明确 TCP 协议的核心价值 —— 理解其设计原理,才能在开发中合理运用。

1.1 TCP 与 HTTP 的本质区别

很多开发者混淆 TCP 和 HTTP 的关系:HTTP 是 “应用层协议”,而 TCP 是 “传输层协议”——HTTP 建立在 TCP 之上,相当于 “TCP 的一种使用方式”。

两者的核心差异体现在通信模式:

特性

TCP 协议

HTTP 协议(基于 TCP)

适用场景

连接方式

长连接(建立后保持连接)

短连接(请求完成后关闭连接)

TCP:即时通讯、实时控制;HTTP:接口请求

通信方向

双向通信(客户端与服务器互发)

单向请求(客户端发,服务器回)

TCP:聊天消息;HTTP:获取商品列表

数据格式

无固定格式(需自定义)

有固定格式(请求头、响应体)

TCP:灵活传输二进制 / 文本;HTTP:结构化数据

可靠性保障

自带重传、排序机制

依赖 TCP 的可靠性

两者均适合需要可靠传输的场景

例如:微信聊天用 TCP(需实时双向收发消息),而获取朋友圈用 HTTP(主动请求后等待响应)。

1.2 TCP 的 “三次握手” 与 “四次挥手”

TCP 的 “可靠性” 源于其连接建立和关闭的严谨流程:

  • 三次握手(建立连接)
  1. 客户端发送 “连接请求”(SYN);
  2. 服务器回复 “同意连接”(SYN+ACK);
  3. 客户端确认 “收到回复”(ACK)。

作用:确保客户端和服务器的发送、接收能力均正常。

  • 四次挥手(关闭连接)
  1. 客户端发送 “关闭请求”(FIN);
  2. 服务器回复 “收到请求”(ACK);
  3. 服务器发送 “准备关闭”(FIN);
  4. 客户端回复 “确认关闭”(ACK)。

作用:确保双方都已完成数据传输,避免数据丢失。

在 Android 开发中,这些流程由系统底层实现,开发者无需手动处理,但需理解:TCP 连接建立有延迟(约 100-300ms),频繁建立 / 关闭连接会影响性能。

1.3 Android 中 TCP 的核心类

Android 通过 Java 的java.net包提供 TCP 支持,核心类包括:

类名

作用

关键方法

Socket

客户端套接字(与服务器建立连接)

getInputStream() getOutputStream()

ServerSocket

服务器端套接字(监听客户端连接)

accept()(阻塞等待连接)

InputStream

从 Socket 读取数据

read(byte[] buffer)

OutputStream

向 Socket 写入数据

write(byte[] buffer)

注意:Android 中ServerSocket多用于本地服务(如 APP 内的进程间通信),实际开发中客户端通常连接远程服务器(用Socket即可)。

二、Android 中 TCP 客户端实现:从连接到通信

实现 TCP 客户端的核心步骤是 “建立连接→读写数据→关闭连接”,但需注意 Android 的主线程限制(网络操作不能在主线程执行)。

2.1 基本 TCP 客户端框架

以下是一个可复用的 TCP 客户端基类,包含连接、发送、接收功能:

public class TcpClient {
    private static final String TAG = "TcpClient";
    private Socket mSocket; // TCP连接对象
    private InputStream mInputStream; // 输入流(读数据)
    private OutputStream mOutputStream; // 输出流(写数据)
    private boolean isConnected; // 连接状态标记
    private String mHost; // 服务器IP
    private int mPort; // 服务器端口
    private OnDataReceivedListener mDataListener; // 数据接收回调

    // 回调接口(数据接收、连接状态变化)
    public interface OnDataReceivedListener {
        void onDataReceived(byte[] data); // 收到数据
        void onConnectSuccess(); // 连接成功
        void onConnectFailed(Throwable e); // 连接失败
        void onDisconnect(); // 断开连接
    }

    public TcpClient(String host, int port, OnDataReceivedListener listener) {
        mHost = host;
        mPort = port;
        mDataListener = listener;
    }

    // 建立连接(必须在子线程调用)
    public void connect() {
        new Thread(() -> {
            try {
                // 关闭已有连接(避免重复连接)
                if (mSocket != null && mSocket.isConnected()) {
                    mSocket.close();
                }

                // 创建Socket,连接服务器(超时时间5秒)
                mSocket = new Socket();
                mSocket.connect(new InetSocketAddress(mHost, mPort), 5000);

                // 获取输入输出流
                mInputStream = mSocket.getInputStream();
                mOutputStream = mSocket.getOutputStream();

                // 更新连接状态
                isConnected = true;
                // 通知UI连接成功(切换到主线程)
                MainLooper.runOnUiThread(mDataListener::onConnectSuccess);

                // 启动接收数据的线程
                startReceiveThread();

            } catch (Exception e) {
                // 连接失败
                isConnected = false;
                MainLooper.runOnUiThread(() -> mDataListener.onConnectFailed(e));
                e.printStackTrace();
            }
        }).start();
    }

    // 接收数据的线程(循环读取)
    private void startReceiveThread() {
        new Thread(() -> {
            byte[] buffer = new byte[1024]; // 缓冲区(根据需求调整大小)
            int length;
            try {
                // 循环读取,直到连接断开
                while (isConnected && (length = mInputStream.read(buffer)) != -1) {
                    // 复制有效数据(避免缓冲区多余内容)
                    byte[] data = new byte[length];
                    System.arraycopy(buffer, 0, data, 0, length);
                    // 回调通知收到数据
                    MainLooper.runOnUiThread(() -> mDataListener.onDataReceived(data));
                }
            } catch (Exception e) {
                // 读取失败(通常是连接已断开)
                e.printStackTrace();
            }

            // 跳出循环表示连接已断开
            disconnect();
        }).start();
    }

    // 发送数据(必须在子线程调用)
    public void sendData(byte[] data) {
        if (!isConnected || mOutputStream == null) {
            MainLooper.runOnUiThread(() -> 
                Toast.makeText(App.getContext(), "未连接服务器", Toast.LENGTH_SHORT).show()
            );
            return;
        }

        new Thread(() -> {
            try {
                mOutputStream.write(data);
                mOutputStream.flush(); // 立即发送(避免缓冲)
            } catch (Exception e) {
                e.printStackTrace();
                // 发送失败,触发断开连接
                disconnect();
            }
        }).start();
    }

    // 断开连接
    public void disconnect() {
        if (!isConnected) return;

        try {
            isConnected = false;
            if (mInputStream != null) mInputStream.close();
            if (mOutputStream != null) mOutputStream.close();
            if (mSocket != null) mSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 通知UI断开连接
            MainLooper.runOnUiThread(mDataListener::onDisconnect);
        }
    }

    // 判断是否连接
    public boolean isConnected() {
        return isConnected;
    }
}

2.2 客户端使用示例

在 Activity 中初始化并使用 TcpClient:

public class TcpClientActivity extends AppCompatActivity implements TcpClient.OnDataReceivedListener {
    private TcpClient mTcpClient;
    private TextView mStatusTv;
    private EditText mInputEt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp_client);

        mStatusTv = findViewById(R.id.tv_status);
        mInputEt = findViewById(R.id.et_input);

        // 初始化TCP客户端(替换为实际服务器IP和端口)
        mTcpClient = new TcpClient("192.168.1.100", 8080, this);

        // 连接按钮
        findViewById(R.id.btn_connect).setOnClickListener(v -> {
            if (!mTcpClient.isConnected()) {
                mTcpClient.connect();
                mStatusTv.setText("连接中...");
            }
        });

        // 发送按钮
        findViewById(R.id.btn_send).setOnClickListener(v -> {
            String content = mInputEt.getText().toString();
            if (!TextUtils.isEmpty(content)) {
                // 发送字符串(转为字节数组)
                mTcpClient.sendData(content.getBytes(StandardCharsets.UTF_8));
                mInputEt.setText("");
            }
        });

        // 断开按钮
        findViewById(R.id.btn_disconnect).setOnClickListener(v -> {
            if (mTcpClient.isConnected()) {
                mTcpClient.disconnect();
            }
        });
    }

    // 收到数据回调
    @Override
    public void onDataReceived(byte[] data) {
        String message = new String(data, StandardCharsets.UTF_8);
        mStatusTv.append("\n收到服务器:" + message);
    }

    // 连接成功回调
    @Override
    public void onConnectSuccess() {
        mStatusTv.setText("已连接");
        Toast.makeText(this, "连接成功", Toast.LENGTH_SHORT).show();
    }

    // 连接失败回调
    @Override
    public void onConnectFailed(Throwable e) {
        mStatusTv.setText("连接失败:" + e.getMessage());
    }

    // 断开连接回调
    @Override
    public void onDisconnect() {
        mStatusTv.setText("已断开");
        Toast.makeText(this, "连接已断开", Toast.LENGTH_SHORT).show();
    }

    // 页面销毁时断开连接
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTcpClient != null) {
            mTcpClient.disconnect();
        }
    }
}

2.3 核心代码解析

上述框架已处理 Android 开发中的关键问题:

  1. 主线程规避
  • 连接、发送、接收操作均在子线程执行;
  • 回调到 UI 层时用MainLooper.runOnUiThread切换主线程。
  1. 资源管理
  • 连接前关闭已有连接,避免资源泄漏;
  • 断开连接时关闭所有流和 Socket;
  • Activity 销毁时主动断开连接。
  1. 状态管理
  • isConnected标记连接状态,避免重复操作;
  • 所有操作前检查连接状态,防止空指针。

三、TCP 服务器搭建:本地测试必备

开发阶段需本地服务器调试,以下是用 Java 实现的简易 TCP 服务器(可运行在 PC 或 Android 设备):

public class TcpServer {
    private ServerSocket mServerSocket;
    private boolean isRunning;
    private List<Socket> mClientSockets = new ArrayList<>(); // 存储客户端连接

    public void start(int port) {
        isRunning = true;
        new Thread(() -> {
            try {
                // 启动服务器,监听指定端口
                mServerSocket = new ServerSocket(port);
                System.out.println("服务器已启动,端口:" + port);

                // 循环接收客户端连接
                while (isRunning) {
                    Socket clientSocket = mServerSocket.accept(); // 阻塞等待连接
                    synchronized (mClientSockets) {
                        mClientSockets.add(clientSocket);
                    }
                    System.out.println("新客户端连接,当前数量:" + mClientSockets.size());

                    // 启动线程处理该客户端
                    handleClient(clientSocket);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    // 处理客户端通信
    private void handleClient(Socket clientSocket) {
        new Thread(() -> {
            try {
                InputStream inputStream = clientSocket.getInputStream();
                OutputStream outputStream = clientSocket.getOutputStream();
                byte[] buffer = new byte[1024];
                int length;

                // 接收客户端数据
                while ((length = inputStream.read(buffer)) != -1) {
                    byte[] data = new byte[length];
                    System.arraycopy(buffer, 0, data, 0, length);
                    String message = new String(data, StandardCharsets.UTF_8);
                    System.out.println("收到客户端:" + message);

                    // 回复客户端
                    String response = "服务器已收到:" + message;
                    outputStream.write(response.getBytes(StandardCharsets.UTF_8));
                    outputStream.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 客户端断开连接
                try {
                    clientSocket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (mClientSockets) {
                    mClientSockets.remove(clientSocket);
                    System.out.println("客户端断开,当前数量:" + mClientSockets.size());
                }
            }
        }).start();
    }

    // 停止服务器
    public void stop() {
        isRunning = false;
        try {
            if (mServerSocket != null) {
                mServerSocket.close();
            }
            synchronized (mClientSockets) {
                for (Socket socket : mClientSockets) {
                    socket.close();
                }
                mClientSockets.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("服务器已停止");
    }

    public static void main(String[] args) {
        TcpServer server = new TcpServer();
        server.start(8080); // 启动服务器,端口8080
    }
}

使用方法:

1.在 PC 上运行main方法启动服务器;

2.Android 客户端连接 PC 的 IP(如192.168.1.101)和端口8080;

3.客户端发送消息,服务器会自动回复。

四、实战关键问题:从 “能跑” 到 “稳定”

基础框架能实现通信,但实际场景中需解决以下问题:

4.1 断线重连机制

网络波动会导致 TCP 连接断开,需自动重连:

// 在TcpClient中添加重连逻辑
private int mReconnectCount = 0; // 重连次数
private static final int MAX_RECONNECT = 5; // 最大重连次数

// 修改disconnect方法,触发重连
private void disconnect() {
    if (!isConnected) return;

    // ... 原有关闭资源代码 ...

    // 判断是否需要重连(未主动断开且未超过最大次数)
    if (isNeedReconnect && mReconnectCount < MAX_RECONNECT) {
        mReconnectCount++;
        MainLooper.runOnUiThread(() -> 
            mStatusTv.setText("断开连接,第" + mReconnectCount + "次重连...")
        );
        // 延迟1秒重连(避免频繁尝试)
        new Handler(Looper.getMainLooper()).postDelayed(this::connect, 1000);
    } else {
        mReconnectCount = 0; // 重置计数
        MainLooper.runOnUiThread(mDataListener::onDisconnect);
    }
}

// 添加主动断开标记(避免主动断开后重连)
private boolean isNeedReconnect = true;

public void disconnect(boolean initiative) {
    isNeedReconnect = !initiative; // 主动断开则不重连
    disconnect();
}

使用时:

  • 网络异常断开:自动重连(最多 5 次);
  • 用户主动点击断开:调用disconnect(true),不重连。

4.2 数据粘包与拆包问题

TCP 是 “流式传输”,多次发送的小数据可能被合并(粘包),大数据可能被拆分(拆包)。例如:

  • 客户端连续发送 “Hello” 和 “World”,服务器可能收到 “HelloWorld”(粘包);
  • 客户端发送 1000 字节数据,服务器可能分两次收到 500 字节(拆包)。

解决方案:自定义数据协议,添加 “数据长度” 头:

// 发送时添加长度前缀(4字节表示长度)
public void sendDataWithHeader(byte[] data) {
    if (data == null) return;

    // 总长度 = 4(长度) + 数据长度
    byte[] totalData = new byte[4 + data.length];
    // 转换长度为4字节(大端模式)
    byte[] lengthBytes = ByteBuffer.allocate(4).putInt(data.length).array();
    // 拼接长度和数据
    System.arraycopy(lengthBytes, 0, totalData, 0, 4);
    System.arraycopy(data, 0, totalData, 4, data.length);

    // 发送带头部的数据
    sendData(totalData);
}

// 接收时按长度解析
private byte[] mReceiveBuffer = new byte[0]; // 缓存未解析数据

private void handleReceivedData(byte[] newData) {
    // 合并缓存和新数据
    byte[] allData = new byte[mReceiveBuffer.length + newData.length];
    System.arraycopy(mReceiveBuffer, 0, allData, 0, mReceiveBuffer.length);
    System.arraycopy(newData, 0, allData, mReceiveBuffer.length, newData.length);

    int index = 0;
    // 循环解析完整数据包
    while (index + 4 <= allData.length) {
        // 读取长度(4字节)
        int dataLength = ByteBuffer.wrap(allData, index, 4).getInt();
        // 检查是否有完整数据包
        if (index + 4 + dataLength > allData.length) {
            break; // 数据不完整,退出循环
        }

        // 提取有效数据
        byte[] data = new byte[dataLength];
        System.arraycopy(allData, index + 4, data, 0, dataLength);
        // 回调通知
        MainLooper.runOnUiThread(() -> mDataListener.onDataReceived(data));

        // 移动索引
        index += 4 + dataLength;
    }

    // 保存未解析的数据到缓存
    if (index < allData.length) {
        mReceiveBuffer = new byte[allData.length - index];
        System.arraycopy(allData, index, mReceiveBuffer, 0, mReceiveBuffer.length);
    } else {
        mReceiveBuffer = new byte[0]; // 清空缓存
    }
}

使用时:

  • 发送:调用sendDataWithHeader("消息内容".getBytes());
  • 接收:在onDataReceived中调用handleReceivedData(data)解析。

4.3 心跳检测机制

长时间无数据传输时,TCP 连接可能被路由器 / 服务器关闭(默认超时约 30-120 秒),需定期发送心跳包维持连接:

// 在TcpClient中添加心跳机制
private Handler mHeartbeatHandler = new Handler(Looper.getMainLooper());
private static final long HEARTBEAT_INTERVAL = 30 * 1000; // 30秒一次

// 连接成功后启动心跳
private void startHeartbeat() {
    mHeartbeatHandler.postDelayed(mHeartbeatRunnable, HEARTBEAT_INTERVAL);
}

private Runnable mHeartbeatRunnable = new Runnable() {
    @Override
    public void run() {
        if (isConnected) {
            // 发送心跳包(自定义格式,如0x01)
            sendData(new byte[]{0x01});
            // 继续定时
            mHeartbeatHandler.postDelayed(this, HEARTBEAT_INTERVAL);
        }
    }
};

// 断开连接时停止心跳
private void stopHeartbeat() {
    mHeartbeatHandler.removeCallbacks(mHeartbeatRunnable);
}

服务器收到心跳包后需回复确认,客户端未收到回复则判断连接异常。

4.4 数据加密传输

TCP 传输内容明文可见,敏感数据(如密码、支付信息)需加密。推荐使用 AES 对称加密:

// AES加密工具类
public class AesUtils {
    private static final String KEY = "1234567890abcdef"; // 16位密钥(实际需安全存储)

    // 加密
    public static byte[] encrypt(byte[] data) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(data);
    }

    // 解密
    public static byte[] decrypt(byte[] encryptedData) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(encryptedData);
    }
}

// 使用加密发送
public void sendEncryptedData(String content) {
    try {
        byte[] data = content.getBytes(StandardCharsets.UTF_8);
        byte[] encrypted = AesUtils.encrypt(data);
        sendDataWithHeader(encrypted);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// 接收解密
@Override
public void onDataReceived(byte[] data) {
    try {
        byte[] decrypted = AesUtils.decrypt(data);
        String message = new String(decrypted, StandardCharsets.UTF_8);
        // 处理解密后的消息
    } catch (Exception e) {
        e.printStackTrace();
    }
}

注意:密钥需通过安全方式传输(如首次连接用 RSA 加密密钥),避免硬编码泄露。

五、Android 特有限制与适配

Android 系统对网络和后台运行有特殊限制,需针对性处理。

5.1 网络权限与明文传输

  • 添加权限:在AndroidManifest.xml中声明网络权限:
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 检测网络状态 -->

  • Android 9 + 明文传输限制

Android 9(API 28+)默认禁止 HTTP/TCP 明文传输,需在AndroidManifest.xml中添加配置:

<application
    android:usesCleartextTraffic="true"> <!-- 允许明文传输 -->
</application>

生产环境建议使用 SSL/TLS 加密(如SSLSocket替代Socket)。

5.2 后台保活与电量优化

TCP 长连接会消耗电量,需平衡实时性和功耗:

  • 屏幕关闭时降低心跳频率
    // 监听屏幕状态
    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
                // 屏幕关闭,心跳改为60秒一次
                stopHeartbeat();
                mHeartbeatHandler.postDelayed(mHeartbeatRunnable, 60 * 1000);
            } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
                // 屏幕开启,恢复30秒心跳
                stopHeartbeat();
                mHeartbeatHandler.postDelayed(mHeartbeatRunnable, 30 * 1000);
            }
        }
    };

  • 网络类型适配
    // 检测网络类型(WIFI/移动网络)
    private boolean isWifiConnected() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        return info != null && info.isConnected();
    }
    
    // WIFI下30秒心跳,移动网络下60秒
    long interval = isWifiConnected() ? 30000 : 60000;

5.3 进程保活(可选)

对于核心功能(如即时通讯),需避免进程被杀死导致连接断开:

  • 使用前台服务
    public class TcpService extends Service {
        private TcpClient mTcpClient;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // 启动前台服务(显示通知,降低被杀死概率)
            Notification notification = createNotification();
            startForeground(1, notification);
    
            // 初始化TCP连接
            mTcpClient = new TcpClient("host", 8080, listener);
            mTcpClient.connect();
            return START_STICKY; // 被杀死后尝试重启
        }
    
        // 创建前台通知
        private Notification createNotification() {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "tcp_channel");
            // 设置通知内容(省略)
            return builder.build();
        }
    }

  • 在 Manifest 中声明服务
    <service
        android:name=".TcpService"
        android:foregroundServiceType="dataSync" /> <!-- Android 10+需指定类型 -->

六、TCP 在 Android 中的典型应用场景

掌握 TCP 的适用场景,才能在开发中做出合理选择:

6.1 即时通讯(如聊天 APP)

核心需求:实时双向收发消息,支持文字、图片、语音。

实现要点:

  • 用 TCP 长连接维持在线状态;
  • 自定义协议区分消息类型(文字 0x01、图片 0x02);
  • 消息加解密保护隐私;
  • 断线重连确保消息不丢失。

6.2 文件上传下载

核心需求:稳定传输大文件(如视频、安装包)。

实现要点:

  • 分块传输(每次发送 4KB,避免内存溢出);
  • 带校验(每块添加 MD5,确保完整性);
  • 断点续传(记录已传输位置,支持暂停后继续);
  • 进度反馈(通过 TCP 发送已传输百分比)。

6.3 智能家居控制

核心需求:手机实时控制设备(如灯光、空调)。

实现要点:

  • 短指令传输(如 “开灯” 对应 0x01 指令);
  • 快速响应(心跳间隔 5-10 秒);
  • 状态同步(设备状态变化主动通知手机);
  • 重连优先级高(确保控制指令能送达)。

七、总结:TCP 开发的核心原则

在 Android 中使用 TCP 协议,需牢记以下原则:

1.连接管理是核心

  • 建立连接:处理超时、网络异常;
  • 维持连接:心跳检测、断线重连;
  • 关闭连接:释放资源、避免泄漏。

2.数据传输需严谨

  • 解决粘包拆包:定义协议头;
  • 确保数据完整:校验和、重传机制;
  • 保护数据安全:加密传输。

3.适配 Android 特性

  • 避免主线程:所有网络操作放子线程;
  • 平衡功耗:根据网络 / 屏幕状态调整心跳;
  • 遵守系统限制:权限、后台运行规则。

TCP 协议的灵活性使其能适应多种场景,但也要求开发者处理更多底层细节。掌握本文的框架和问题解决方案,可大幅降低开发难度,实现稳定可靠的 TCP 通信功能。

最后提醒:TCP 并非万能 —— 简单的接口请求优先用 HTTP(Retrofit 可直接实现),只有需要实时双向通信时,才选择 TCP。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Monkey-旭

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值