TCP协议与流通信


TCP协议与流通信

文章插图
 
TCP(Transportation Control Protocol)协议与IP协议是一同产生的 。事实上,两者最初是一个协议,后来才被分拆成网络层的IP和传输层的TCP 。我们已经在UDP协议中介绍过,UDP协议是IP协议在传输层的“傀儡”,用来实现数据包形式的通信 。而TCP协议则实现了“流”形式的通信 。
TCP的内容非常丰富 。我不能在一篇文章中将TCP讲完 。这一篇主要介绍TCP协议的下面几个方面:
1. “流”通信的意义与实现方式
2. 如何实现可靠传输
3. 使用滑窗提高效率
“流”通信
TCP协议是传输层协议,实现的是端口到端口(port)的通信 。更进一步,TCP协议虚拟了文本流(byte stream)的通信 。在linux文本流中我们谈到,计算机数据的本质是有序的0/1序列 (如果以byte为单位,就叫做文本流) 。计算机的功能就是储存和处理文本流 。CPU + memory + 存储设备实现了文本流在同一台计算机内部的加工处理 。通过一些IO,比如屏幕和键盘,文本流实现了人机交互 。而进一步,如果网络通信可在不同计算机之间进行文本流的交互,那么我们就和整个计算机系统的数据处理方式实现了对接 。
IP协议(参考协议森林03, 05)和UDP协议采用的是数据包的方式传送,后发出的数据包可能早到,我们并不能保证数据到达的次序 。TCP协议确保了数据到达的顺序与文本流顺序相符 。当计算机从TCP协议的接口读取数据时,这些数据已经是排列好顺序的“流”了 。比如我们有一个大文件要从本地主机发送到远程主机,如果是按照“流”接收到的话,我们可以一边接收,一边将文本流存入文件系统 。这样,等到“流”接收完了,硬盘写入操作也已经完成 。如果采取UDP的传输方式,我们需要等到所有的数据到达后,进行排序,才能组装成大的文件 。这种情况下,我们不得不使用大量的计算机资源来存储已经到达的数据,直到所有数据都达到了,才能开始处理 。
“流”的要点是次序(order),然而实现这一点并不简单 。TCP协议是基于IP协议的,所以最终数据传送还是以IP数据包为单位进行的 。如果一个文本流很长的话,我们不可能将整个文本流放入到一个IP数据包中,那样有可能会超过MTU 。所以,TCP协议封装到IP包的不是整个文本流,而是TCP协议所规定的片段(segment) 。与之前的一个IP或者UDP数据包类似,一个TCP片段同样分为头部(header)和数据(payload)两部分 (“片段”这个名字更多是起提醒作用:嘿,这里并不是完整的文本流) 。整个文本流按照次序被分成小段,而每一段被放入TCP片段的数据部分 。一个TCP片段封装成的IP包不超过整个IP接力路径上的最小MTU,从而避免令人痛苦的碎片化(fragmentation) 。
(给文本流分段是在发送主机完成的,而碎片化是在网络中的路由器完成的 。路由器要处理许多路的通信,所以相当繁忙 。文本流提前在发送主机分好段,可以避免在路由器上执行碎片化,可大大减小网络负担)
TCP协议与流通信

文章插图
 
片段与编号
TCP片段的头部(header)会存有该片段的序号(sequence number) 。这样,接收的计算机就可以知道接收到的片段在原文本流中的顺序了,也可以知道自己下一步需要接收哪个片段以形成流 。比如已经接收到了片段1,片段2,片段3,那么接收主机就开始期待片段4 。如果接收到不符合顺序的数据包(比如片段8),接收方的TCP模块可以拒绝接收,从而保证呈现给接收主机的信息是符合次序的“流” 。
可靠性
片段编号这个初步的想法并不能解决我们所有的问题 。IP协议是不可靠的,所以IP数据包可能在传输过程中发生错误或者丢失 。而IP传输是"Best Effort" 式的,如果发生异常情况,我们的IP数据包就会被轻易的丢弃掉 。另一方面,如果乱序(out-of-order)片段到达,根据我们上面说的,接收主机不会接收 。这样,错误片段、丢失片段和被拒片段的联手破坏之下,接收主机只可能收到一个充满“漏洞”的文本流 。
TCP协议与流通信

文章插图
 
请补上漏洞
TCP的补救方法是,在每收到一个正确的、符合次序的片段之后,就向发送方(也就是连接的另一段)发送一个特殊的TCP片段,用来知会(ACK,acknowledge)发送方:我已经收到那个片段了 。这个特殊的TCP片段叫做ACK回复 。如果一个片段序号为L,对应ACK回复有回复号L+1,也就是接收方期待接收的下一个发送片段的序号 。如果发送方在一定时间等待之后,还是没有收到ACK回复,那么它推断之前发送的片段一定发生了异常 。发送方会重复发送(retransmit)那个出现异常的片段,等待ACK回复,如果还没有收到,那么再重复发送原片段... 直到收到该片段对应的ACK回复(回复号为L+1的ACK) 。


推荐阅读