在Socket编程中,为了应对网络拥塞,TCP协议采用了拥塞控制机制。主要包括:
- 慢开始:初始时拥塞窗口cwnd较小,然后以指数增长方式逐渐增大,监测网络拥塞情况。
- 拥塞避免:如果检测到网络拥塞, shrinking cwnd以减小发送速率,避免进一步拥塞。
- 快重传:在发生丢包时快速重传,以减少浪费的带宽。
- 快恢复:在拥塞结束后快速恢复到拥塞前的传输速率。
处理TCP拥塞控制主要方法有:
- 设置慢开始门限ssthresh:在连接初始化时设置慢开始阈值,到达该阈值后采用拥塞避免算法。
- 爆发确认:在接收到连续3个重复确认时进入快速重传,设置cwnd为ssthresh的一半并重传丢失的包。
- 定时更新拥塞窗口:根据RTT和丢包情况定期更新cwnd和ssthresh。
- 丢包 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);
}
}