TCP协议详解
TCP协议
T C P提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用T C P的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个T C P连接。
TCP首部结构
TCP封装

TCP结构

- 源/目的端口号:这两个值加上I P首部中的源端I P地址和目的端I P地址唯一确定一个T C P连接。一个I P地址和一个端口号也称为一个插口( s o c k e t)。
- 32位序号:序号用来标识从T C P发端向T C P收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节。
- 32位确认序号:接收到的TCP包序号+1
- 6位标志位:置1表示有效
- URG:紧急指针有效
- ACK:确认序号有效
- PSH:接收方应该尽快将这个报文段交给应用层。
- RST:重建连接
- SYN:同步序号,用于建立一个连接
- FIN:发送端完成发送任务
- 16位窗口大小:允许同时发送/接收的数据包的个数
- 16位校验和:同ip校验和
- 16位紧急指针:
TCP建立连接

- 客户机:标志位SYN=1,32位序号 = client_isn(客户端初始序号)
- 服务器:标志位SYN=1,32位序号 = server_isn(服务器初始序号) 32位确认序号 = client_isn+1 //确认客户端连接
- 客户端:标志位SYN=0,32位序号 = server_isn+1//确认服务端连接
说明
- 握手包中没有数据
- 初始32位序号(ISN)随机生成
- 除了SYN 其它标志位为0
- 初始化过程中,32位确认号无效(ACK = 0)
- 每一次握手都发送一个包
- 只有处于LISTEN的进程能够接收新的连接请求,但不能接收数据报文段
- 处于ESTABLISHED的进程将不能接收SYN报文段
TCP断开连接
假设服客户端为主动关闭端

- 客户端:标志位FIN=1,32位序号 = client_seq,数据中包含EOF符号
- 服务器:32位确认序号 = client_seq+1
- 服务器:标志位FIN=1,32位序号 = server_seq
- 客户端:32位确认序号 = server_seq+1
TCP状态转移图

2MSL的意义?
:当T C P执行一个主动关闭,并发回最后一个A C K,该连接必须在T I M E WA I T状态停留的时间为2倍的M S L。这样可让T C P再次发送最后的A C K以防这个A C K丢失(另一端超时并重发最后的F I N)
TCP选项

- kind:选型表类型,可选值0、1、2、3、8
- len:当前选项长度(单位字节),包括kind和len字节
TCP交互数据流
交互式输入如Rlogin远程登录通常每一个交互按键都会产生一个数据分组,也就是说,每次从客户传到服务器的是一个字节的按键(而不是每次一行)。

经受时延
通常T C P在接收到数据时并不立即发送A C K;相反,它推迟发送,以便将A C K与需要沿该方向发送的数据一起发送(有时称这种现象为数据捎带ACK)。绝大多数实现采用的时延为200 ms,也就是说,TCP将以最大200 ms 的时延等待是否有数据一起发送。
Nagle算法
在一个Rlogin连接上客户一般每次发送一个字节到服务器,这就产生了一些41字节长的分组:20字节的I P首部、20字节的TCP首部和1个字节的数据。在广域网上,这些小分组则会增加拥塞出现的可能。
Nagle算法:要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组。
有时我们也需要关闭Nagle算法。一个典型的例子是X窗口系统服务器:小消息(鼠标移动)必须无时延地发送,以便为进行某种操作的交互用户提供实时的反馈。
TCP成块数据流
滑动窗口

- 发送方
- 拥塞窗口大小:SWS
- 上一次收到的确认包序号:LAR
- 上一次发送的包序号:LFS
- 满足LFS-LAR<=SWS
- 接收方
- 接收窗口大小:RWS
- 上一次收到的确认包序号:LAR
- 上一次发送的包序号:LFS
- 满足LFS-LAR<=RWS
随着数据的收发,数据包序号不断的增加,窗口不断的向右滑动,窗口滑动过程会丢弃“太过超前”的高序号数据包,“等待”低序号数据包,实现数据包的排序。
慢启动算法
网络拥塞:如果发送方一开始便向网络发送多个报文段,直至达到接收方通告的窗口大小为止。当发送方和接收方处于同一个局域网时,这种方式是可以的。但 是如果在发送方和接收方之间存在多个路由器和速率较慢的链路时,就有可能出现一些问题。一些中间路由器必须缓存分组,并有可能耗尽存储器的空间。
步骤
- 当与另一个网络的主机建立T C P连接时,拥塞窗口被初始化为1个报文段
- 发送方开始时发送一个报文段,然后等待ACK。当收到该ACK时,拥塞窗口从1增加为2,当收到这两个报文段的ACK时,拥塞窗口就增加为4。这是一种指数增加的关系。
- 当在某些点上可能达到了互联网的容量,于是中间路由器开始丢弃分组。
- 这就通知发送方它的拥塞窗口开得过大
TCP超时重发
TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。T C P通过在发送时设置一个定时器来解决这种问题。如果当定时器超时的时候还没有收到确认,它就重传该数据。TCP超时与重传中最重要的部分就是对一个给定连接的往返时间(RTT)的测量。由于路由器和网络流量均会变化,因此我们认为这个时间可能经常会发生变化,TCP应该跟踪这些变化并相应地改变其超时时间。
拥塞避免算法
但是当拥塞发生时,我们希望降低分组进入网络的传输速率,于是可以调用慢启动来作到这一点,所以在实际中这两个算法通常在一起实现。
流程:
拥塞避免算法和慢启动算法需要对每个连接维持两个变量:
拥塞窗口cwnd 慢启动门限ssthresh
- 对一个给定的连接,初始化cwnd为1个报文段,ssthresh为65535个字节。
- TCP输出例程的输出不能超过c w n d和接收方通告窗口的大小
- 当拥塞发生时(超时或收到重复确认),ssthresh被设置为当前窗口大小的一半( cwnd和接收方通告窗口大小的最小值,但最少为2个报文段)
- 当新的数据被对方确认时,就增加cwnd
- 如果cwnd<=ssthresh,则正在进行慢启动。这会使窗口按指数方式增长:发送1个报文段,然后是2个,接着是4个
- 否则在进行避免拥塞启动,那么每次收到一个确认时将cwnd增加1 /cwnd。与慢启动的指数增加比起来,这是一种加性增长(additive increase)

快速重传算法
定义:假如一些报文段的重新排序,则在重新排序的报文段被处理并产生一个新的ACK之前,只可能产生1 ~ 2个重复的A C K。如果一连串收到3个或3个以上的重复AC K,就非常可能是一个报文段丢失了。于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出。
重新分组
定义:当TCP超时并重传时,它不一定要重传同样的报文段。相反,TCP允许进行重新分组而发送一个较大的报文段,这将有助于提高性能(当然,这个较大的报文段不能够超过接收方声明的M S S)。
TCP坚持定时器
如果一个ACK包丢失了,则双方就有可能因为等待对方而使连接终止:
接收方等待接收数据(因为它已经向发送方通告了一个非0的ACK窗口)
发送方在等待允许它继续发送数据的窗口(ACK窗口)更新。
为防止这种死锁情况的发生,发送方使用一个坚持定时器(persist timer)来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查(windowprobe)。
糊涂窗口综合症
基于窗口的流量控制方案,如T C P所使用的,会导致一种被称为“糊涂窗口综合症”(Silly Window Syndrome),如果发生这种情况,则少量的数据将通过连接进行交换,而不是满长度的报文段。
TCP保活定时器
保活功能主要是为服务器应用程序提供的。服务器应用程序希望知道客户主机是否崩溃,从而可以代表客户使用资源。许多版本的Rlogin和Telnet服务器默认使用这个选项。