可靠与效率
TCP的主要特点:
- TCP是面向连接的运输层协议,每一条TCP连接只能有两个端点,即:点对点、一对一形式。每一个端口都是一个socket。
- TCP提供可靠交付的服务
- TCP提供全双工通信,因为TCP的收发缓冲区是分开的。
- TCP面向字节流。流指的是流入或流出进程的字节序列。面向字节流指的是尽管应用程序与TCP的交互是一次一个数据块,但TCP仅仅认为接收到的数据是无结构的字节序列。
- TCP不关心应用程序一次把多长的报文发送到TCP缓存,只根据对方给出的窗口值与当前网络的拥塞程度来决定一个报文段应包含多少个字节,形成TCP报文段。
1、可靠传输及错误处理
可靠传输过程:
发送方A每发送完成一个分组就会停止发送,等待接收方B返回确认信号。发送方A接收到确认信号后再开启下一次的分组发送。
发送方如何处理通信错误的问题:
使用超时重传的方式解决。发送方A发送之后,通过接收方B返回的确认信号是否正常接收。在A中会为每一个们组设置一个超时计时器,只有在计时器范围内接收到了B的信号,才会进行下一个分组的发送,如果没有收到B的确认信号,则重传该分组。
4种通信错误:
- 分组错误:B收到A发送的分组后,经过检验发现该分组不能使用,此时B不会发送确认信号
分组错误其实就是发来的数据有问题。
- 分组丢失:B根本就没有收到A发送的分组,此时B肯定不会发送确认信号。
分组丢失其实就是发送的数据丢了。
- 确认丢失:B发送了确认,但A没收到。此时A会重发数据
情况1:A重发,B收到的数据错误,不会发送确认。这种情况直到B收到正确为止
情况2:A重发,B收到了正确数据,B丢弃重复的数据,并发送确认。该错误结束
- 确认迟到:B发送了确认,但A收到的时候已经超时了。此时A会重发数据
情况1:A重发,B收到的数据错误,不会发送确认。这种情况直到B收到正确为止
情况2:A重发,B收到了正确数据,B丢弃重复的数据,并发送确认。
A接收到确认丢弃重复的确认信号
2、提高效率的方式
提高传输效率的方式:
采用流水线传输,即:在发送分组和等待确认这个时间段中,发送方不断发出多个分组。
连续ARQ协议与滑动窗口协议采用该种方式来提高传输效率。这两个协议是TCP的子协议。
流水线传输的实现:
- 发送窗口
发送窗口是规定一个范围,这个范围就叫做窗口。在这个窗口内的分组可以被连续发送出去,而不需要等待对方确认。如下图,就是一个大小为5的窗口,这12345个分组将会被连续发出。
- 发送窗口滑动
发送窗口滑动,就是动态的移动窗口。当接收方收到一个确认,代表有一个分组被传输完成,此时便可以将窗口向前移动一个分组。如下图,就是当接收方接收到分组1返回的确认信号后,就可以将这个窗口向前移动到红框位置。
- 累计确认
因为流水线传输这种方法是将分组连续发出,那么接收方也是连续接收到数据。当在一个处理周期内,接收到了多个正确的数据,那么接收方只需要发送最后一个数据的确认来代表全部分组的确认,而不是每个分组都发一个确认。
如下图,当接收方连续接收到M2、M3、M4、M5时,并不是发送4个确认信号,而是发送一个M5的确认信号代表这四个数据都收到了。M5这个确认信号就是累计确认。
3、包头设计
TCP报文段整体框图:
在下图中可以看到,TCP报文段包含TCP首部(包头)和TCP数据这两部分。
TCP首部包含上方蓝色区域的部分,其中有20个字节是固定的,在这20个字节后可以去主动添加"选项"这个内容,"填充"部分是为了使得"选项"内容进行字节对齐。
TCP数据包含下方绿色和橙色区域,由IP首部和IP数据这两部分构成。
TCP包头大小如何计算:
TCP首部的大小至少20个字节,这20个字节是固定的首部。之后有更多数据("选项-填充"部分)可以继续向下加,新的数据大小应该是4n个字节,如果不够4n个字节将补齐。即:TCP首部的大小应该是4的正数倍。
数据偏移是指定TCP报文段中数据开始的位置,这其实也是指TCP包头的大小。数据偏移占4个bit,因此范围是0~15,包头大小与数据偏移的关系为:大小 = 数据偏移 * 4 。例如数据偏移=5,那么包头大小就是5*4=20个字节。
序号与确认号如何计算:
- 序号:当前发送的分组序号,这是第一个字节的编号(有且仅有第一个分组是随机的)。
- 确认号:发送分组之后接收端返回的确认信号,确认信号 = 序号 + 收到的数据个数
假设这个分组序号是100,这也代表第一个字节的编号是100,那么第二个字节编号就是101,依次类推。假如这个数据有200个字节,那么接收方最终收到的字节的序号就是100+200-1=299,最终返回的确认号就是299+1=300。同时这个300代表了下一个分组序号为300。
TCP包头其他内容解释:
- 源端口:存放了发送端的端口信息。16位,与博文"端口号"章节中叙述的规则一致。
- 目的端口:存放了接收端的端口信息。16位
- URG:1代表使能紧急指针,0代表无效
- 紧急指针:紧急数据存放在TCP数据的靠前的一段,紧急指针就是指定哪一部分是紧急数据。
- ACK:1代表确认号有效,0代表无效
- PSH:1代表数据已传输完成,可以交给应用进程,0代表无效
- RST:1代表通信中出现严重问题,TCP数据中断,0代表无效
- SYN:1代表发起连接请求(三次握手),0代表无效
- FIN:1代表断开连接请求(四次挥手),0代表无效
- 窗口:流水线传输法中的窗口,数值代表窗口的大小
- 检验和:检验TCP的数据是否正确。
TCP的连接管理
1、三次握手
什么是三次握手:
握手就是TCP建立连接的过程,三次握手指的是TCP采用的连接方式是三报文握手,在客户端与服务器之间交换三个TCP报文段。目的是防止已失效的连接请求报文段突然又传输到了,因而产生TCP连接建立错误。
注意:对于建立连接,只能由客户端发起。
三次握手避免连接错误的过程:
1、服务器启动,准备接收客户端的连接请求
2、客户端启动,向服务器发送连接请求报文段,这个报文段称为SYN报文段。
包头的SYN=1(请求连接),序号seq=x(随机值)
注意1:SYN报文段不允许携带数据,但会消耗一个序号。正常情况下是收到一个字节的数据,才消耗掉一个序号。
3、服务器收到客户端的SYN报文段后,如果同意连接则发回确认报文段,这也是一个SYN报文段
包头的SYN=1,ACK=1(代表确认),确认号ack=x+1,序号seq=y(随机值)
注意1:seq=y的y指的是服务器端数据的序号,与第2点seq=x的x做一个区分。客户端与服务器发送的数据序号是独立的,互相没有关系的。
注意2:确认信号ack = 序号 + 收到的数据个数,在这里,SYN报文段没有携带数据但是需要消耗一个序号,即:假设收到的数据个数为1。因此ack=x+1
注意3:ACK=1代表确认信号,不是说服务器收到了确认信号,而是将ACK=1发给客户端,客户端收到确认报文段中,能够解析出ACK=1,从而得知服务器发送了确认信号。
4、客户端收到服务器的SYN报文段后,向服务器再发送一次确认信号。这个报文是ACK报文段
包头的ACK=1,序号seq=x+1(第一次SYN报文段时是x),确认信号ack=y+1(同理 3-注意2)
注意:当客户端发送了SYN报文段,并收到服务器的确认报文段之后,就代表连接建立。
当服务器发送了SYN报文段,并收到了客户端的确认报文段后,就代表连接建立。
注意:ACK报文段可以携带数据,如果不携带数据则不消耗序号。
2、四次挥手
什么是四次挥手:
挥手就是TCP断开连接的过程,四次挥手指的是TCP采用的连接方式是四报文挥手。
注意:对于断开连接,客户端和服务器都可以发起。
什么是三次挥手:
三次挥手就是在服务器收到客户端的FIN报文段后,将确认信号与包含数据的报文段一并发给客户端的情况。这样原本确认信号、包含数据的报文段需要两步,现在就只需要了一步,这就使得四次挥手变成了三次挥手。
四次挥手避免连接错误的过程:
1、客户端向服务器发送释放报文段,这个报文段是FIN报文段。
包头的FIN=1,序号seq=u(u就是正常的该传哪一个信号)
注意:FIN报文段不携带数据,但消耗一个序号。
注意:此时客户端终止 "客户端->服务器" 的通信
2、服务器收到FIN报文段后,返回确认信号。
包头的ACK=1,确认号ack=u+1
注意:此时服务器得知了 "客户端->服务器" 的通信已经断开,但服务器处于半关闭状态。
3、服务器如果有数据,则继续向客户端发送数据报文段 ,这是FIN报文段
包头的FIN=1,ACK=1,序号seq=w,确认号ack=u+1
4、 客户端收到服务器发送的确认信号和数据报文段后,向服务器发送确认信号。
包头的ACK=1,序号seq=u+1,ack=w+1
注意:此时客户端得知了 "服务器->客户端" 的通信已经断开。
注意:此时客户端并不会立刻断开连接,而是等待2MSL后才真正断开连接。MSL就是最大报文生存周期,就是"可靠传输"章节的定时器。
5、服务器收到客户端的确认信号后,半连接状态断开。
注意:此时服务器真正断开连接
什么是半关闭状态:
半关闭状态就是指如果服务器并没有完全关闭,如果服务器在接收到FIN报文段,发送确认信号之后,依旧有信号要发送,那么将会再向客户端发送一个包含数据的报文段。
当数据大小不是很大时,通常将包含数据的报文段与确认信号报文段合并一起,一并发出。
客户端等待2MSL后才真正关闭的原因:
当客户端接收到服务器的FIN数据报后,向服务器发送确认信号,这个确认信号的生存周期就是MSL。
因为TCP的可靠传输性质,当服务器在MSL之后还未收到客户端发来的确认信号,那么服务器就认为通信出错(就是"可靠传输"-"4种通信错误"中的错误),就会重新发送一个FIN数据报。这个重新发送的数据报的生存周期是MSL。
这意味这如果客户端在发送确认信号后2MSL时间范围内收到了又一个FIN数据报,那么代表通信错误,客户端将再次向服务器发送确认信号,之后重复等待2MSL这个逻辑。
保活计时器:
保活计时器的目的是防止TCP连接中出现长时期的空闲,通常设置为2h。
当到达2h还没有通信时,服务器会自动向客户端发送一个探测报文段,去测试客户端是否还正常连接。如果发送了10个探测报文段后,客户端仍没有回应,服务器就认为客户端故障,主动终止连接。