TCP (Transmission Control Protocol,传输控制协议)
流量控制
一条TCP连接的双方主机都为该连接设置了接收缓存。当该TCP连接收到正确、按序的字节后,它就将数据放入接收缓存。相关联的应用进程会从该缓存中读取数据,但没必要数据刚一到达就立刻读取。事实上,接收方应用也许正忙于其他任务,甚至要过很长时间后才去读取该数据。如果应用程序读取数据时相当缓慢,而发送方发送数据太多、太块,会很容易使该连接的接收缓存溢出。
TCP为应用程序提供了流量控制服务以消除发送方使接收方缓存溢出的可能性。因此,可以说流量控制是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读速率相匹配。
TCP通过让发送方维护一个称为接收窗口(receive window)的变量来提供流量控制。
- RcvBuffer为该连接分配了一个接收缓存
- LastByteRead为接收主机上的应用进程从缓存读出的数据流最后一个字节的编号
- LastByteRcvd为从网络中到达的并且已放入接收主机接收缓存中的数据流最后一个字节的编号
- LastByteSend为发送主机发送的最后的一个字节的编号
- LastByteAcked为发送主机接收的最后一个确认号序号
由于TCP不允许已分配的缓存溢出,所以下式成立:
LastByteRcvd - LastByteRead <= RcvBuffer
接收窗口用RcvWindow表示,根据缓存可用空间的数量来设置:
RcvWindow = RcvBuffer - [LastByteRcvd - LastByteRead]
由于该空间是随着时间变化的,所以RcvWindow是动态的。
发送主机在该连接的整个生命周期必须保证:
LastByteSend - LastByteAcked <= RcvWindow
注:TCP仅在它有数据或确认要发时才会发送报文段。
TCP规约中要求:当主机B的接收窗口为0时,主机A继续发送只有一个字节数据的报文段。这些报文段将会被接收方确认。最终缓存将开始清空,并且确认报文里将包含一个非0的RcvWindow值。
TCP连接管理
假设运行在一台主机(客户机)上的一个进程想与另一台主机(服务器)上的一个进程建立一条连接。客户机应用进程首先通知客户机TCP,它想建立一个与服务器上某个进程之间的连接。客户机中的TCP会用以下方式与服务器中的TCP建立一条TCP连接:
- 第一步: 客户机端的TCP首先向服务器端的TCP发送一个特殊的TCP报文段。该报文段中不包含应用层数据,但是报文段的首部中的一个标志位(即SYN比特)被置为1。因此,这个特殊报文段被称为SYN报文段。另外,客户机会选择一个起始序号(client_isn),并将其放置到该起始的TCP SYN报文段的序号字段中。该报文段会被封装在一个IP数据报中,并发送给服务器。为了避免某些安全性攻击,在适当地随机化选择client_isn方面有不少研究成果。
- 第二步: 一旦包含TCP SYN报文段的IP数据报到达服务器主机(假定它的确到达了),服务器会从该数据报中提取出TCP SYN报文段,为该TCP连接分配TCP缓存和变量,并向客户机TCP发送允许连接的报文段。这个允许连接的报文段也不包含应用层数据。但是,在报文段的首部却包含3个重要的信息。首先,SYN比特被置为1。其次,该TCP报文段首部的确认号字段被置为client_isn+1。最后,服务器选择主机的初始序号(server_isn),并将其放置到TCP报文段首部的序号字段中。这个允许连接的报文段实际上表明了:“我收到了你要求建立连接的、带有初始序号client_isn的SYN分组。我同意建立该连接。我自己的初始序号是server_isn。”该允许连接的报文段有时被称为SYNACK报文段(SYNACK segment)。
- 第三步: 在收到SYNACK报文段后,客户机也要给该连接分配缓存和变量。客户机主机还会向服务器发送另外一个报文段,这个报文段对服务器的允许连接的报文段进行了确认(客户机通过将值server_isn+1放置到TCP报文段首部的确认字段中来完成此项工作)。因为连接已经建立了,所以该SYN比特被置为0。
一旦以上3步完成,客户机和服务器主机就可以相互发送含有数据的报文段了。在以后的每一个报文段中,SYN比特都将被置为0。
天下没有不散的宴席,对于TCP连接也是如此。参与一条TCP连接的两个进程中的任何一个都能终止该连接。当连接结束后,主机中的“资源”(即缓存和变量)将被客户释放。举一个例子,假设某客户打算关闭 连接,如图3-40所示。客户应用进程发出一个关闭连命令。这会引起客户TCP向 服务器进程发送一个特殊的TCP报文段。 这个特殊的报文段让其首部中的一个标志位即FIN比特(参见图3-29)被设置为l。当服务器接收到该报文段后,就向发送方回送一个确认报文段。然后,服务器发送它自己的终止报文段,其FIN比特置为1。最后2该客户对这个服务器的终止报文段进行确认。此时,在两台主机上用 于该连接的所有资源都被释放了。