TCP/IP协议族的传输层协议主要包括TCP和UDP。TCP是面向连接的可靠的传输协议。它支持在并不可靠的网络上实现面向连接的可靠数据传输。UDP是无连接的传输协议,主要用于支持在校可靠的链路上的数据传输,或用于对延迟敏感的应用。

TCP/IP传输层的作用

wKioL1ZqjBvDq5JDAAEp8hPswHw000.jpg

TCP/IP的传输层位于应用层和网络层之间,为终端主机提供端到端的连接。TCP/IP的传输层有TCP和UDP两种主要协议。TCP和UDP都基于相同的网络层协议IP。传输层协议的主要作用:

  • 提供面向连接或无连接的服务:传输层协议定义了通信两端点之间是否需要建立可靠的连接关系。

  • 维护连接状态:如果必须在通信前建立连接关系,传输层协议必须在其数据库中记录这种连接关系,并且通过某种机制维护连接关系,及时发现连接故障灯。

  • 对应用层数据进行分段和封装:应用层数据往往是大块的或持续的数据流,而网络只能发送长度有限的数据包,传输层协议必须在船上应用层数据之前将其划分成适当尺寸的段(segment),再交给IP协议发送。

  • 实现多路复用(Multiplexing):一个IP地址可以标识一个主机,一对“源-目的”IP地址可以标识一对主机的通信关系,而一个主机上却可能同时有多个程序访问网络,因此传输层协议采用端口号(port number)来标识这些上层的应用程序,从而使这些程序可以复用网络通道。

  • 可靠地传输数据:数据在跨网络传输过程中可能出现错误、丢失、乱序等种种问题,传输层协议必须能够检测并更正这些问题。

  • 执行流量控制(flow control):当发送方的发送速率超过接收方的接收速率时,或者当资源不足以支撑数据的处理时,传输层负责将流量控制在合理的水平;反之,当资源允许时,传输层可以放开流量,使其增加到适当的水平。

TCP协议基本原理

TCP协议的特点

wKiom1Zqj6TDLOEjAAE0KmJyyAs987.jpg

RFC793定义的TCP是一种面向连接的、端到端的可靠传输协议。TCP的主要特点包括:

  • 三次握手(Three-Way Handshake)建立连接:确保连接建立的可靠性。

  • 端口号:通过端口号标识上层协议和服务,实现了网络通道的多路复用。

  • 完整性校验:通过对协议和载荷数据计算校验和(Checksum),保证了接收方能检测出传输过程中可能出现的差错。

  • 确认机制:对于正确接收到的数据,接收方通过显式应当通告发送方,超出一定时间之后,发送方将重传没有被确认的段,确保传输的可靠性。

  • 序列号:发送的所有数据都拥有唯一的序列号,这样不但唯一标识了每一个段(segment),而且明确了每个段在整个数据流中的位置,接收方可以利用这些信息实现确认、丢失检测、乱序重排等功能。

  • 窗口机制:通过可调节的窗口,TCP接收方可以通告期望的发送速度,从而控制数据的流量。

TCP封装

wKiom1ZuawyBa4iWAAOeRbNuRAs242.jpgTCP段的头格式如上图所示,其协议头最少20个字节。其中主要字段如下:

  • 源端口(Source Port):16位的源端口字段包含初始化通信的端口号。源端口和源IP地址的作用是标识报文的返回地址。

  • 目的端口(Destination Port):16位的目的端口字段定义传输的目的。这个端口指明接收方计算机上的应用程序接口。

  • 序列号(Sequence Number):该字段用来标识TCP源端设备向目的端设备发送的字节流,它表示在这个报文段中的第一个数据字节。如果将字节流看作在两个应用程序间的单向流动,则TCP用序列号对每个字节进行计数。序列号是一个32位的数。

  • 确认号(Acknowledgement Number):TCP使用32位的确认号字段标识期望收到的下一个段的第一个字节,并声明此前的所有数据都已经正确无误地收到,因此,确认号应该是上次已成功收到的数据字节序列号加1.收到确认号的源计算机会知道特定的段已经被收到。确认号的字段只在ACK标志被设置时才有效。

  • 数据偏移(Data Offset):这个4位字段包括TCP头大小,以32位数据结构为单位。

  • 保留(Reserved):6位置0的字段。为将来定义新的用途保留。

  • 控制位(Control Bits):共6位,每1位标志可以打开一个控制功能,者六个标志从左至右是URG(Urgent Pointer field signficant 紧急指针字段标志)、ACK(Acknowledgement field significant 确认字段标识)、PSH(Push Function 推功能)、RST(Reset the connection 重置连接)、SYN(Synchronize sequence numbers 同步序列号)、FIN(No more data from sender 数据传送完毕)。

  • 窗口(Window):目的主机使用16位的窗口字段告诉源主机它期望每次收到的数据的字节数。窗口字段是一个16位字段。

  • 校验和(Checksum):TCP头包括16位的校验和字段用于错误检查。源主机基于部分IP头信息、TCP头和数据内容计算一个校验和,目的主机也要进行相同的计算,如果收到的内容没有错误过,两个计算结果应该完全一样,从而证明数据的有效性。

  • 紧急指针(Urgent Pointer):紧急指针字段是一个可选的16位指针,指向段内的最后一个字节位置,这个字段只在URG标志被设置时才有效。

  • 选项(Option):至少1字节的可变长字段,标识哪个选项(如果有的话)有效。如果没有选项,这个字节等于0,说明选项字段的结束。这个字节等于1表示无需再有操作;等于2表示下四个字节包括源机器的最大段长度(Maximum Segment Size,MSS),MSS是数据字段中可包含的最大数据量,源和目的机器对此达成一致。当一个TCP连接建立时,连接的双方都要通告各自的MSS,协商可以传输的最大段长度。常见的MSS有1024字节,以太网可达1460字节。

  • 数据(Data):从技术上讲,它并不是TCP头的一部分,但应该了解到,数据字段位于紧急指针和/或选项字段之后,填充字段之前。字段的大小是最大的MSS,MSS可以在源和目的机器之间协商。数据段可能比MSS小,但不能比MSS大。

  • 填充(Padding):这个字段中加入额外的零,以保证TCP头是32位的整数倍。

TCP/UDP端口号

wKioL1ZudcuwVXCTAAFRPLDLaXU551.jpg

    在IP网络中,一个IP地址可以唯一地标识一个主机。但一个主机上却可能同时又多个程序访问网络,要标识这些程序,只用IP地址就不够了。因此TCP/UDP采用端口号来标识这些上层的应用程序,从而使这些程序可以复用网络通道。而为了区分TCP和UDP协议,IP用协议号6标识TCP,用协议号17标识UDP。

在实际的端到端通信中,通信的双方实际上是两个应用程序,者两个程序都需要用各自的端口号来进行标识。所有,一个通信连接可以用双方的IP地址以及双方的端口号来标识,而每一个数据报内也必须包含源IP地址、源端口、目的IP地址和目的端口。IP地址在IP头中标出,而端口号在TCP/UDP头中标出。

    TCP/UDP的端口号是一个16位二进制数,即端口号范围可以为0~65535。其中,端口0~1023由IANA(Internet Assigned Number Authority ,Internet号码分配机构)统一管理,分配或保留众所周知的服务使用,这些端口称为众所周知端口(Well-known Port).大于1023的端口号没有统一的管理,可以由应用程式任意使用。详细分配信息可参考RFC1700。

TCP连接的建立

wKioL1Zuekqx3qE3AAF2TgDi6CY557.jpg

由于TCP使用的网络层协议IP只提供不可靠、无连接的传送服务,为确保连接的建立和终止都是可靠的,TCP使用三次握手(Three-Way Handshake)的方式来建立可靠的连接。TCP使用报头中的SYN(Synchronization Segment,同步段)来描述创建一个连接的三次握手。另外,握手过程确保TCP只有在两端一致同意的情况下,才会打开一个连接。

TCP的三次握手建立连接的过程如下:

  1. 由发起方HostA向被叫方HostB发出连接请求。将段的序列号标为a,SYN置为。由于是双方发的第一包,ACK无效。

  2. HostB收到连接请求后,读出序列号为a,发送序列号为b的包,同时将ACK置为有效,将确认号置为a+1,同时将SYN置位。

  3. HostA收到HostB的连接确认后,对该确认再次作确认。HostA收到确认号为a+1、序列号为b的包后,发送序列号为a+1、确认号b+1的段进行确认。

  4. HostB收到确认报文后,连接建立。

这样,一个双向的TCP连接就建立好了,双方可以开始传输数据。

TCP连接的拆除

wKiom1ZyZczA6btMAAGFc2jAwNg182.jpg

TCP用FIN(Finish Segment,结束段)来描述关闭一个连接的消息。

上图所示是一个常规的TCP连接终止过程。当数据传输结束后,需要端口连接,其过程描述如下:

  1. HostA要求终止连接,发送序列号为p的段,FIN置为有效,同时确认此前刚收到的段。

  2. HostB收到HostA发送的段后,发送ACK端,确认号为p+1,同时关闭连接。

  3. HostB发送序列号为q的段,FIN置为有效,通知连接关闭。

  4. HostA收到HostB发送的段后,发送ACK端,确认号为q+1,同时关闭连接。

TCP连接至此终止。可见这是一个四次握手过程。

TCP可靠传输机制

传输确认

wKiom1ZyZ8PjPhZLAAHWjddweUs797.jpg

    为保证数据传输的可靠性,TCP要求对传输的数据进行确认。TCP协议通过序列号和确认号来确保传输的可靠性。每一次传输数据时,TCP都会标明该段的起始序列号,一遍对方确认。在TCP协议中并不直接确认收到那些段,而是通知发送方下一次该发送哪一个段,表示前面的段都已收到。序列号还可以帮助接收方对乱序到达的数据进行排序。

  收到一个段确认一个段的方法虽然简单,但是会消耗网络资源较多。为了提高通信效率,TCP采取了一些提高效率的方法。

    首先,TCP并不要求对每个段一对一地发送确认。接收端可以用一个ACK确认之前收到的所有数据。例如,接收到的确认序列号为N+1时,表示接收方对到N为止的所有数据全部正确接收。

    另外,TCP并不要求必须单独发送确认,而是允许将确认放在传输给对方的TCP数据段中。如果收到一个段后没有段要马上传到对方,TCP通常会等待一个微小的延时,希望将确认与后续的数据段合并发出。

    由于每个段都有唯一的编号,这样当对方收到了重复的段时容易发现,数据段丢失后也容易定位,乱序后也可以重新排列。在动态路由网络中,一些数据包很可能经过不同的路径,因此报文可能会乱序到达。32位的序列号由接收端计算机用于把段的数据重组成最初形式。

    上图给出了一个经过简化的TCP传输过程示例。为了便于理解,本例只关注从HostA到HostB的单向传输。架设HostA向HostB发送的初始序列号为1,且发送窗口为4096字节,HostA向HostB发送的每个段数据长度为1024字节,HostA将一次性向HostB发送4个段。而HostB收到并校验了数据的正确性后,在回送确认时只需发送确认号4096+1=4097,就可以表示4096之前的全部数据都已经正确接收,下一次期望接收从4097开始的数据。下一次,HostA仍然一次发送总量为4096字节的4个段给HostB。

超时重传

wKioL1ZzYgzAP2V5AAIBsnxhHlk136.jpg

    上图给出了一个经过简化的典型的TCP重传过程示例。假设HostA向HostB发送的序列号为1025的第二个段在途中丢失。HostB只对全部按序无错接收到的序列号最高的给以确认,即HostB只以确认号1025向HostA确认第一个段已收到。

    HostA在收到这个确认时,并不能确定HostB没有收到第二个段,因为也许第二个段还没有到达HostB,或者HostB发出的第二个确认可能被延迟了,因此,HostA不能立即重传第二个段。只有在第二个段发出超过RTT(Round Trip Time 往返时间)而仍没有收到确认时,HostA才认为这个段已经丢失,并重传这个段。

    HostB收到重传的第二个段后,按序无误收到的最后一个段的序列号为3073,因此向HostA发送确认号为4097,表示之前的数据均正确无误地收到。

    TCP接收方并不通过“错误通知”告知发送方重传。如果HostA向HostB发送的序列号为1025的第二个段到达HostB,但被检查出校验错误,HostB也不会向HostA发送“错误通知”要求重传。因此,RTA仍然需要等待RTT时间后再重传这个段。

    必须考虑的另一种情况是,HostB回送的确认段也同样可能在传输中丢失或出错。此时对HostA来说并不需求额外的机制,因为HostA面临的现象与此前的例子是完全相同的——没有收到确认。HostA仍然用同样的超时重传机制来处理即可。而如果HostB回送的确认只是被延迟,则HostA在重传后就可能收到两个确认,此时HostA只需要忽略多余的确认即可。

    因此,RTT时间就成为一个非常重要的参数。过大的RTT导致TCP重传非常迟缓,可能会降低传输的速度;过小的RTT则会导致TCP频繁重传,同样降低资源的使用效率。在实际实现中,TCP通过实时跟踪发送的段与其相应确认之间的时间间隔来动态调整RTT的数值。

滑动窗口

wKioL1ZzZreCI0FBAAIFFcGHPfI610.jpg

    TCP使用大小可变的滑动窗口,并定义了窗口尺寸的通告机制,以增强流量控制的功能。这些机制为TCP提供了在终端系统之间调整流量的动态方法。

    TCP滑动窗口尺寸的单位为字节,起始于确认字段指明的值,这个值是接收端正期望一次性接收的字节。窗口尺寸是一个16位字段,因而窗口最大为65535字节。在TCP的传输过程中,双方通过交换窗口的大小来表达自己剩余的缓冲却空间,以及下一次能够接受的最大的数据量,避免缓冲区的溢出。

    上图仍然通过数据单向发送的简化示例,介绍TCP如何通过滑动窗口实现流量控制。

    假定初始的发送窗口大小为4096,每个段的数据为1024字节,则HostA每次发送4个段给HostB。HostB正确接收到这些数据后,应该以确认号4097进行确认。然而同时,HostB由于缓存不足或处理能力有限,认为这个发送速度过快,并期望将窗口降低一半。此时HostB在回送的确认中将窗口降低到2048,要求HostA每次只发送2048字节。HostA收到这个确认后,便依照要求降低了发送窗口尺寸,也就降低了发送速度。

    若接收方设备要求窗口大小为0,表明接收方已经接收了全部数据,或者接收方应用程序没有时间读取数据,要求暂停发送。

    TCP运行在全双工模式,所以发送者和接收者可能在相同的线路上同时发送数据,但发送的方向相反。这暗示着,每个终端系统对每个TCP链接包含两个窗口,一个用于发送,一个用于接收。

    可变滑动窗口解决了端到端流量控制问题,但是无法干预网络。如果中间节点,例如路由器被阻塞,则没有任何机制可以通知TCP。如果特定的TCP实现对超时设定和再传输具有抵抗性,则会极度增加网络的拥挤程度。