[TOC]
一、TCP协议的主要特点
- 支持面对连接的传输服务
- 支持全双工通信
- 支持同时建立多个并发的TCP连接
- 支持可靠的传输服务
- 支持字节流的传输
二、TCP报文的首部格式
- 序号:指出本TCP报文段数据载荷的第一个字节的序号
- 确认号:指出希望收到对方下一个TCP报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有数据的确认
- 数据偏移:4比特,最大表示154字节。*用来指出TCP报文段的数据载荷部分的起始处距离TCP报文段的起始处有多远</u>
- 校验和:在计算校验和时候,要在TCP报文段的前面加上12字节的伪首部
复位标识符RST:用来复位TCP连接
- 当RST=1时,表明TCP连接出现了异常,必须释放连接,然后再重新建立连接。
- RST=1还能用来拒绝一个非法的报文段或拒绝打开一个TCP连接
紧急指针:占16比特,用来指明紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立即封装到一个TCP报文段中进行发送
选项:
- 最大报文段长度MSS选项:TCP报文段数据载荷部分的最大长度
- 窗口扩大选项
- 时间戳选项:
- 用来计算往返时间RTT
- 用来处理序号超范围的情况,又称为防止序号绕回PAWS
- 选择确认选项
填充:由于选项的长度可变,因此使用填充来确保报文段首部能被4整除,因为数据偏移字段是以4字节为单位
TCP连接的三个阶段:
- 建立TCP连接
- 数据传送
- 释放TCP连接
三、TCP连接的建立
TCP连接的建立需要解决的三个问题:
- 使TCP双方能够确认对方的存在
- 使TCP双方能够协商一些参数
- 使TCP双方能够对运输实体资源进行分配
TCP使用”三次握手“建立连接
为什么TCP客户进程最后还要发送一个普通的TCP确认报文段呢?
假设我们改为“两次握手”来建立TCP的连接,则可能出现一种情况。如果上一次的TCP连接请求因为各种原因延迟到达,在这期间,客户端又发起一次TCP连接请求,并建立连接。在进行数据传输后释放了连接。结果在这段时间延迟的TCP连接请求已经失效,但上一次延迟的TCP连接可能才到达,并且服务器向客户端发送报文并处于连接已建立的状态,而客户端因为没有再发送连接请求,所以不会理会该报文。此时就出现客户端处于未连接状态,而服务器端处于连接状态。
如果是“三次握手”,因为多了一步连接确认报文。TCP连接请求失效后,收到服务器端发送的报文,将不会理会。服务器端因为没有接收到报文,则连接无法建立!
四、TCP连接的释放
1. 注意点:
当服务器端发送TCP确认报文段后,服务器端的TCP连接将会断开,然后再向客户端发送TCP释放请求,而不是整个过程结束后客户端和服务器端一起断开连接。
MSL(Maximum Segment Lifetime):最长报文段寿命,一般设置为2min。也就是说客户端在进入TIME-WAIT状态,还要经过4min才能进入关闭状态
2. 为什么不直接进入CLOSED状态,而是要先进入TIME-WAIT
如果在最后客户端向服务器端发送的TCP确认报文段没有到达客户端。那么超时后,客户端将重新发送TCP连接释放报文。但是此时如果已经进入CLOSE状态,并不会理会该报文。然后客户端一指发送TCP连接释放报文,一直处于LAST-ACK状态
3. 保活计时器
TCP服务器进程没收到一次TCP客户进程的数据,就重新设置并启动保活计时器(2小时定时)
若保活计时器定时周期内未收到TCP客户进程发送的数据,则当保活计时器到时后,TCP进程就像TCP客户进程发送一个探测报文,以后每隔75秒发一次,十次后仍无TCP客户进程的回应,TCP服务器进程就认为TCP客户进程在主机发送故障,关闭这个连接
五、TCP可靠传输
TCP基于以字节为单位的滑动窗口来实现可靠传输
可靠传输的实现
- 发送方的发送窗口并不总是和接收方的接收窗口一样大
- 对于不按序到达的数据,TCP通常将数据临时存放在接收窗口,等到字节流中缺少的字节收到后,再按序交付上层的应用进程
- TCP要求接收方必须有累计确认和稍带确认机制。接收方不应该过分的推迟确认,否则会导致发送方不必要的超时重传。确认推迟的时间不应超过0.5s。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就发送一个确认。
- TCP接收双方都有接收窗口和发送窗口
选择确认
它允许TCP接收方有选择地确认失序报文段,而不是累积的确认最后一个正确接收地有序报文段。
当将该机制与选择重传(SR)机制结合起来使用时(即跳过重传那些已被接收方选择性确认过地报文段),Tcp看起来就像我们通常使用地SR协议,所以TCP地差错恢复机制也许最好分类为GBN协议与SR协议地混合体
六、TCP的流量控制
所谓流量控制,就是让发送方的发送速率不要太快,要让接收方来得及接收
大概的过程如下描述:
假设一开始的rwnd为400字节
- 发送1~100号字节,还能发送300字节
- 发送101~200号字节,还能发送200字节
- 发送201~300号字节,但丢失了,还能发送100字节
- 接收方返回ACK=201,表示1~200号字节收到,rwnd=100+200=300号字节
- 发送301~400号字节,还能发送100号字节,因为之前的201~300号字节还没有确认
- 发送401~500号字节,不能发送新的数据了
- 超时重传201~300号字节
- 接收方返回ACK=301,还能发送100字节
- 发送501~600号字节,不能再发生新的数据了
- 接收方处理以前的数据,rwnd调整为0
在rwnd=0后,如果接收方处理完数据发送ACK给发送方时的报文丢失,那么就会陷入死锁,即发送方等待接收方的确认报文,接收方等待发送方发新的数据。
为了解决这个问题,TCP要求:当接收方的接收窗口为0时,发送方继续发送只有一个字节数据的报文段。这些报文段将会被接收方确认,最终缓存清空,并在确认报文里将包含一个非0的rwnd值