传输控制协议
UDP本身不包含可靠传输机制,它们可能会使用一种像校验或CRC这样的数学函数来检测接收到有差错的数据,但它们不尝试去纠正差错。事实上,UDP和IP也没有实现差错纠正,协议只是提供一定次数的重试,如果仍不成功则放弃。
发送方向接收方发送一条消息,通信媒介可能会丢失传递的消息。计算机网络的研究就是在解决这样的问题。香农给出了该课题在信息论上的理论研究方案,比特的概念就是在这个时期(1948)年普及的。
对于有损信道中的数据传输,一种解决方案是信息论和编码论技术上的结合,使用差错校正码将信道上发生错误的bit纠正过来。另一种方案是“重新发送”,直到信息最终被接收,这种方法称为自动重复请求(Automatic Repeat Request, ARQ),正式这一简单理念构成了TCP通信协议的基础。
1. ARQ和重传
一种简单的解决方法就是,尝试重新发送,直到信息最终被接收,这种方法称为自动重复请求(Automatic Repeat Request, ARQ)。
一个直接处理分组丢失和比特差错的方法是重发分组直到它被正确接收。基本形式是:发送方发送一个分组,等待一个ACK;当接收方接收该分组时,它发送对应的ACK;当发送方接收到这个ACK,它再发送另一个分组。
以上操作会涉及一些问题:(1)发送方对一个ACK应该等待多长时间?(2)如果ACK丢了怎么办?(3)如果分组被接收到了,里面有错怎么办?
2. TCP服务模型
TCP提供了一种面向连接的、可靠的字节流服务。
面向连接:TCP两个应用程序必须在它们可交换数据之前,通过相互联系来建立一个TCP连接。
字节流服务:TCP提供一种字节流抽象概念给应用程序使用。例如,应用程序在一端写入10字节,随后20字节,在随后50字节;在另一端的应用程序不知道这个细节,它可能会以每次20字节分四次读入这80字节,即一端给TCP输入字节流,同样的字节流会出现在另一端,每个端点独立选择自己的读和写大小。
2.1. TCP头部和封装
TCP在IP数据报中的封装如下:
TCP头部经常是20字节,加上选项的话(最大段大小、时间戳、窗口缩放和SACK),TCP头部可达60字节。TCP头部相比UDP头部更加复杂,它必须保证连接的每一端都知道同步的最新状态。
- 在TCP术语中,一个IP地址和一个端口号的组合被称为套接字。每个TCP连接由一对套接字(四元组:客户端IP地址、客户端port、服务器IP地址、服务器port)唯一标识。
- 数据流上每个字节都有一个序列号。
- 确认号是被接收的数据字节的序列号加1,这个字段只有在ACK位字段被启用的情况下才有效,这个ACK位字段通常用于除初始和末尾报文段之外的所有报文段。
- 当建立一个新连接时,从客户机发送至服务器的第一个报文段的SYN位字段被启用,这样的报文段称为SYN报文段。序列号指本次连接的这个方向上要使用的第一个序列号,后续序列号和返回的ACK号也在这个方向上。
- TCP可以描述为“一种带累积正向确认的滑动窗口协议”。ACK号字段被构建用于指明在接收方已经顺序收到的最大字节(+1)。例如,字节1-1024已经接收成功,而下一个报文段包含字节2049-3072,那么接收方不能使用常规的ACK号字段去发信息告诉发送方它接收到了这个新报文段。现代TCP有一个选择确认(SACK)选项,可以允许接收方告诉发送方它正确的接收到了次序杂乱的数据。当与一个具有SACK能力的TCP发送方搭配时,性能会显著提升。
- 头部长度字段给出头部长度,以32位为单位,占4字节,TCP被限制为只能带60字节的头部,而不带选项大小为20字节。
2.2. TCP连接管理
TCP是一种面向连接的单播协议。发送数据之前,通信双方必须在彼此间建立一条连接。
创建连接
-
一个TCP连接由一个4元组构成,它们分别是两个IP地址和两个端口号,即通信的每一端都由一个套接字唯一标识
-
一个TCP连接通常分为三个阶段:启动、数据传输(“连接已建立”)和退出(“关闭”)。
三次握手建立连接:
- 客户端主动发送一个SYN报文段,并指明自己想要连接的端口号和它的客户端初始序列号(ISNC)。
- 服务器也发送自己的SYN报文段作为响应,并包含了它的初始序列号(ISNS);为确认客户端的SYN,服务器将其包含的ISNC数值+1,作为返回的确认号。
- 为确认服务器的SYN,客户端将ISNS的数值+1,作为确认号。
通过发送上述3个报文段就能够完成一个TCP连接的建立,通常将该过程称为三次握手。三次握手的目的不仅让通信双方了解一个连接正在建立,还可以利用数据包的选项承载特殊的信息,交换初始序列号(Initial Sequence Number,ISN)。
关闭连接
- 一个关闭操作是由应用程序提出关闭连接请求而引发的(如系统调用close)。
四次挥手断开连接:
- 主动关闭方发送一个FIN段指明接收者希望看到的自己当前的序列号K;FIN段还包含一个用于确认对方最近一次发送来的数据的ACK。
- 连接的被动关闭者将K数值+1作为响应的确认号,以表明自己已经成功接收到主动关闭者发送的FIN;上层应用程序会被告知连接的另一端已经提出了关闭的请求。
- 被关闭着上层应用发出自己的关闭操作,被动关闭者将身份变为主动关闭者,发送自己的FIN报文,序列号为L。
- 主动关闭者发送上一个FIN的确认号,如果FIN丢失,被动关闭者将重新发送FIN,直到收到ACK。
通过发送上述4个报文段,可关闭一个TCP连接。
2.3. 初始序列号
当一个连接打开时,任何拥有合适的IP地址、端口号、符合逻辑的序列号(即在窗口中)以及正确校验和的报文段都将被对方接收。问题是,在一个连接中,TCP报文段在经过网络路由后可能会存在延迟抵达和排序混乱的情况,为解决这一问题,需要按照一定措施选择初始序列号。
在发送用于建立连接的SYN之前,通信双方会选择一个初始化序列号。初始化序列号会随时间而改变,因此每一个连接都拥有不同的序列号。
一个TCP连接是由一对套接字唯一标识的,因此即使是同一连接也会出现不同实例。如果连接由于某个报文段长时间延迟而被关闭,后又以相同的四元组被打开,延迟的报文段被视为有效数据重新进入新连接的数据流中。
通常会采取一些措施来避免连接实例间的序列号重叠问题,可以将风险降至最低,一个对数据完整性要求高的应用程序,可以在应用程序利用CRC或校验和保证所需数据在传输过程中没有出现任何错误,该方法已被普遍用于大文件传输。
telnet命令建立在TCP连接之上,如telnet 42.101.40.191 80
。