Socket 编程中,如何处理 TCP 的拥塞控制?

在Socket编程中,为了应对网络拥塞,TCP协议采用了拥塞控制机制。主要包括:

  1. 慢开始:初始时拥塞窗口cwnd较小,然后以指数增长方式逐渐增大,监测网络拥塞情况。
  2. 拥塞避免:如果检测到网络拥塞, shrinking cwnd以减小发送速率,避免进一步拥塞。
  3. 快重传:在发生丢包时快速重传,以减少浪费的带宽。
  4. 快恢复:在拥塞结束后快速恢复到拥塞前的传输速率。

处理TCP拥塞控制主要方法有:

  1. 设置慢开始门限ssthresh:在连接初始化时设置慢开始阈值,到达该阈值后采用拥塞避免算法。
  2. 爆发确认:在接收到连续3个重复确认时进入快速重传,设置cwnd为ssthresh的一半并重传丢失的包。
  3. 定时更新拥塞窗口:根据RTT和丢包情况定期更新cwnd和ssthresh。
  4. 丢包 detection:通过定时器检查数据包的确认情况,判断是否发生了丢包。

代码示例:

// 服务端
ServerSocket server = new ServerSocket(8000);
Socket socket = server.accept();

int ssthresh = 64 * 1024;  // 慢开始门限
int cwnd = 2 * 1024;      // 拥塞窗口初始大小
int dupAcks = 0;          // 重复确认计数

InputStream in = socket.getInputStream();
while ((seq = in.read()) != -1) {
    if (seq == nextSeq) {  // 数据包确认
        dupAcks = 0;
        cwnd += 1024;      // 拥塞窗口增大
        nextSeq++;
    } else if (seq > nextSeq) { // 数据包丢失
        dupAcks++;
        if (dupAcks == 3) {    // 爆发确认
            ssthresh = cwnd / 2;
            cwnd = ssthresh;
            retransmitPacket(nextSeq);  // 重传数据包
            nextSeq++;
        }
    } 
}
// 客户端  
Socket socket = new Socket("127.0.0.1", 8000);
OutputStream out = socket.getOutputStream();

int seq = 0;  
while (hasDataToSend) {
    byte[] packet = getPacket(seq++);  // 获取下一个数据包
    out.write(packet);

    int ack = in.read();      // 读取确认
    if (ack == -1) {         // 超时重传
        retransmitPacket(seq - 1);
    } 
}