TCP/IP协议
作者:Danbo 2015-7-2
本文为参考TCP/IP详解卷一,某些知识点加上了作者自己的理解,如有错误,欢迎指正,可以微博联系我!
TCP包格式和IP包格式如下:
TCP的正常建立与关闭
建立连接
TCP协议提供可靠的面向连接服务,采用三次握手建立连接。
第一次握手:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到SYN包,向客户端返回ACK(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RCVD状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据,也就是ESTABLISHED状态。
终止连接
采用四次挥手断开双向连接。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
TCP状态变迁图
客户端的状态可以用一下流程图来表示:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器的状态可以流程图:
CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST->ACK->CLOSED
2MSL等待状态(两个作用)
TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。处理原则:当TCP执行一个主动关闭,并发回最后一个ACK,该链接必须在TIME_WAIT状态停留的时间为2MSL。这样可让TCP有机会在此发送最后一个ACK以防这个ACK丢失(在另一端发送FIN前提)
但是,在连接处于2MSL等待时,任何迟到返回的报文段将被丢弃。因为处于2MSL等待的、由该插口对(socket pair)定义的连接在这段时间内不能被再用,对于客户程序还好 一些,但是对于服务程序,例如httpd,它总是要使用同一个端口80来进行服务,而在 2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间(quit time)的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静等待MSL时间才能进行下一次连接,让后来返回的数据包没有机会影响到发送端,因为返回的包和重新建立的包使用同一个四元组,发送端无法区分这两个包属于不同连接。(建议MSL时间为2min,不过这个与操作系统有关。)
半打开状态(Half-Open)
如果以防已经关闭或异常终止连接而另一方却不知道,我们将这样的TCP连接称为半打开的。这种状态可以通过Keepalive选项来进行发现两一段已经消失。还有一种形式是:本端发送SYN,对端回应ACK+SYN,此时本段不回应ACK。
当处于半打开状态的一方重启并重新连接后,它将丢失复位前的所有信息,因此它并不知道数据报文段中提到的连接。此时就会返回RST(异常终止要发送RST置位的包)包应答,已关闭此次连接。此时只需要等待MSL时间,因为TCP默认机器重启的时间大于MSL。PIX防火墙和IDS入侵检测系统都可以伪装攻击目标发送RST的包去终止异常的TCP连接。(比如限定连接的时间,减少半开连接限制超时时间)当我们Telnet一个不存在的端口号时,本段立马收到一个拒绝访问的包,这个就是对方发送的RST包导致的。
半关闭状态(Half-Close)
单方向链路关闭。即TCP连接一端在结束它的发送后还能接收来自另一端数据的能力。程序调用的是shutdown,而不是close,不过大多数程序都是调用close终止两个方向的连接。
最大报文段长度MSS(Option字段)
最大报文段长度表示TCP传往另一端的最大块数据的长度。当建立一个连接时,每一方都受到对方通告的MSS值(MSS选项只能出现在SYN报文中)。如果一方收不到另一方的MSS值,那么就设为默认的536字节。MSS是最长见的选项字段,还有另一个选项叫做窗口放大因子(Window*Shift Count即可以发送超大的数据包,即乘以目前窗口的倍数为实际一次发送的数据量。解决高速链路和高速主机普通TCP发包过慢问题。)。还有一些HASH值也会放在Option字段。而防火墙默认则会清掉IP和TCP的Option选项字段。
纳格算法
经受时延的确认
一个例子:这里我们将举另外一个例子:在一个交互注册过程中键入中断的一个特殊功能键。这个功能键通常可以产生多个字符序列,经常从ASCII码的转移(escape)字符开始,如果TCP每次得到一个字符,它很可能会发送序列中的第一个字符(ASCII码的ESC),然后缓存其他字符并等待对该字符的确认。但当服务器收到该字符后,它并不发送确认而是继续的等待接受序列中的其他字符。这就会经常触发服务器的经受时延的确认算法,表示剩下的字符没有在200ms内发送。对于交互用户而言,这将产生明显的时延。
注意只有客户端这边有经受时延的确认,因为客户端这边输入的比较慢,服务器那边收到数据就会立即确认。最大等待200ms还没有数据发送的话,客户端就直接返回ACK了。
滑动窗口
TCP采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方有多大的缓存区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据,但是紧急数据除外,例如:允许用户终止在远端机上的运行进程。另一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一字节及发送方的滑动窗口大小。
滑动窗口机制的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口,同时,接收方也维持了一个允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可不同。不同的滑动窗口协议窗口大小一般不同。发送窗口内的序号的上下界不一定要一样,但是还没有被确认的帧,或者是哪些可以被发送的帧。
- 称窗口左边向右边靠近为窗口合拢。这种现象发生在数据被发送和确认时。
- 当窗口右边沿想右移动时将允许发送更多的数据,我们称之为窗口张开。这种先发发送在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。
- 当右边装口左移时,我们称之为窗口收缩。
发送方打开几号窗口表示发送方已经发送了该序列的帧,但是如果没有得到接收方ack确认的话,此时该序号的帧仍然在发送窗口中。接收方方打开几号窗口代表接收端收到几号的帧,但是并没有返回ack确认。当接收方返回该序号的ack时,该序号关闭(合拢),接收方收到ack时,该序号窗口关闭(此时窗口张开,注意始终不能大于通告窗口大小)。
对于发送窗口来说窗口打开代表发送了该序列数据,但没有收到确认,收到ACK后窗口合拢。
对于接受窗口来说窗口打开代表接受了该序列数据,但没有发送确认,当发ACK后窗口合拢。
1比特滑动窗口协议
当发送窗口和接收窗口的大小固定为1时,滑动窗口协议退化为停等协议(stop-and-wait)。该协议规定发送方每发送一帧后就要停下来,等待接收方已正确接收的确认(Acknowledgement)返回后才能继续发送下一个帧。由于发送方需要判断接收到的帧是新习发的帧还是重新发送的帧,因此发送放要为每个帧加一个序号。由于停等协议规定只要一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。
后退n协议
由于停等协议要为每一个帧进行确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。后退n协议中,发送方在发完已给数据帧后 ,不停下来等待应答帧,而是连续发送若干个帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送。且发送方在每发完一个数据帧时都要设置超时定时器。只要在所设置的超时时间内未收到确认帧,就要重发相应的数据帧。如:当发送方发送了N个帧后,若发现该N帧的前一个帧在计时器超后仍未返回其确认信息,该帧被判定为出错或者丢失,此时发送方就不得不重新发送出错帧及其后的N帧。
从这里不难看出,后退n协议一方面因连续发送数据帧而提高了效率,但是另一方面,在重传时又必须把原已正确重传的数据帧进行重传(仅因这些数据这之前有一个数据帧出错),这种做法又使重传效率降低。由此可见,若传输信道的传输质量很差因而导致误码率较大,连续测协议不一定优于停止等待协议。此协议中的发送窗口的大小为k,接收窗口仍未1.
选择重传协议
在后退n协议中,接收*发现错误帧就不再接收后续的帧,及时是正确的帧到达,这显然是一种浪费。另一种效率跟高的策略是当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方扔可收下来,存放在一个缓冲区,同时要求发送方重新传输出错的那一帧。一旦收到重新传来的帧后,就可以源存与缓冲区中国的其余帧一并按正确的顺序递交高层。这种方法称为选择重发(Selectice Repeat),显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。
糊涂窗口综合症
慢启动
TCP超时与重传
拥塞避免算法
快速重传与快速恢复算法
TCP坚持定时器
TCP保活定时器
版权声明:本文为博主原创文章,未经博主允许不得转载。