一、TCP简介
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP基本术语:
- 接收缓冲区:服务端建立连接后,接受的数据会存入内核的接收缓冲区中,然后调用recv系统调用,把接收缓冲区中的数据拷贝到应用程序的内存中,进行处理。
- 发送缓冲区:客户端调用send,把数据拷贝到内核的发送缓冲区,再通过网络把数据发送到服务端。
- 滑动窗口:一 个socket有两个滑动窗口(一个sendbuf、一个recvbuf),两个窗口的大小是通过setsockopt函数设置的。服务端ack请求时会返回接受缓冲区的窗口大小。当窗口大小为0时,表示服务端不能够再接受数据。TCP的滑动窗口大小实际上就是socket的接收缓冲区大小的字节数。
- 重传队列:每一次发送一个片段,片段的一份复制就放在名为重传队列的数据结构中,此时启动重传计时器。如果在片段接收到确认之前计时器超时,就重传片段。
- 累积确认机制:假设片段1长度80,片段2长度120,客户端发送片段1,片段2,服务端收到片段1和片段2,这时服务端会发回一条ack确认消息确认号为201。由于累计确认机制,客户端会认为201之前的消息都被确认过了。
扩展:通过setsockopt函数设置窗口大小。当发送缓冲区满的时候,阻塞式I/O会一直等待,直到服务端返回的窗口大小大于0。
总结:滑动窗口在TCP传输过程起到了流控的作用,重传队列保障了TCP连接的可靠性。
二、TCP传输
TCP数据流的概念划分类别
假设A和B之间新建立了一条TCP连接。设备A需要传送一长串数据流,但设备B无法一次全部接收,所以它限制设备A每次发送分段指定数量的字节数,直到分段中已发送的字节数得到确认。之后,设备A可以继续发送更多字节。每一个设备都对发送,接收及确认数据进行追踪。
如果我们在任一时间点对于这一过程做一个“快照”,那么我们可以将TCP buffer中的数据分为以下四类,并把它们看作一个时间轴:
- 已发送已确认: 数据流中最早的字节已经发送并得到确认。这些数据是站在发送设备的角度来看的。如下图所示,31个字节已经发送并确认。
- 已发送但尚未确认: 已发送但尚未得到确认的字节。发送方在确认之前,不认为这些数据已经被处理。下图所示14字节为第2类。
- 未发送而接收方已Ready: 设备尚未将数据发出,但接收方根据最近一次关于发送方一次要发送多少字节确认自己有足够空间。发送方会立即尝试发送。如图,第3类有6字节。
- 未发送而接收方Not Ready: 由于接收方not ready,还不允许将这部分数据发出。
TCP传输
连接中的服务器发出了四个连续片段(号码从1开始)
- 片段1 序列号字段是1片段长度80。所以片段1中最后一个序列号是80。
- 片段2 序列号是81片段长度是120。片段2中最后一个序列号是200。
- 片段3 序列号是201片段长度是160。片段3中最后一个序列号是360。
- 片段4 序列号是361片段长度是140。片段3中最后一个序列号是500。
过程:
1. 客户端和服务器建立连接,确定接收buffer和发送buffer的大小为555。
2. 服务器发送片段1,片段2,片段3,片段4,片段的一份复制就放在名为重传队列的数据结构中,此时启动重传计时器。
3. 客户端接收片段1,片段2,它会发回一条ack确认消息确认号为201。服务器端收到片段1,片段2的确认消息,然后把它们从重传队列中移除(并且服务器发送窗口右移200字节)。
4. 片段3丢失,客户端接收片段4,客户端将片段4保存在接收buffer中,但是不需要确认,因为TCP是累积确认机制——确认片段4表示片段3也接收到了,但实际上并没有。因此,客户端需要等待片段3。
5. 服务器端片段3的重传计时器会超时,服务器之后重传片段3。之后客户端收到,然后发送片段3和4的ack确认消息确认号为501给服务器。服务器端收到片段3,片段4的确认消息,然后把它们从重传队列中移除(并且服务器发送窗口右移300字节)。
参考资料: