TCP协议详解

作者: veaxen 分类: 网络 发布时间: 2017-05-02 15:42

一、TCP/IP协议族

1.1 四层协议系统

应用层:ping应用程序、telnet远程登陆协议、DNS协议(运行在用户空间)
传输层:TCP、UDP、SCTP(流控制传输协议)
网络层:ICMP、IP
数据链路层:ARP、RARP

关于各层的详细分析,可以参考《互联网协议入门(一)》《互联网协议入门(二)》

二、TCP协议详解

2.1 TCP服务的特点

面向连接、字节流和可靠传输

面向连接:通信双方都必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP连接是全双工的,即双方的数据读写都可以通过一个连接来进行。完成数据交换之后,通信双方都必须断开连接以释放系统资源。

字节流:发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系,应用程序对数据的发送和接收时没有边界限制的。

可靠:首先,TCP协议采用发送应答机制,即发送端的每个TCP报文段都必须得到接收方的应答,才认为这个TCP报文传输成功。其次,TCP协议采用超时重传机制,发送端在每发送一个TCP报文段之后启动定时器,如果在定时时间内未收到应答,它将重发该报文段。最后,因为TCP报文段最终是以ip数据报发送的,而ip数据报到达接收端可能乱序、重复,所以tcp协议还会对接收到的TCP报文段重排、整理,再交付给应用层

2.2 TCP协议头部结构

如下图所示:
这里写图片描述

(1)16位端口号(port number):告知主机该报文是来自哪个端口,以及传给哪个上层协议或应用程序的(目的端口)。

(2)32位序号(sequence number):一次TCP通信(从tcp连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。

(3)32位确认号(acknowledge number):用作对另一方发送来的TCP报文段的相应。

(4)4位头部长度(head length):标识该TCP头部有多少个32bit字(4个字节)。因为4位最多能表示15,所以TCP头部最长是60字节。

(5)6位标志位,包含如下几项:
URG:紧急指针(urgent pointer)是否有效
ACK:标示确认号(acknowledge number)是否有效
PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据。
RST:表示要求对方重新建立连接。我们称携带RST标志的TCP报文为复位报文。
SYN:表示请求建立一个连接。我们称携带SYN标志的TCP报文为同步报文。
FIN:表示通知对方本端要关闭连接了。我们称携带FIN标志的TCP报文为结束报文段。

(6)16位窗口大小(window size):指的是接收通告窗口(Receiver Window)。它告诉对方,本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。

(7)16位检验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否有损坏。

(8)16位紧急指针(urgent pointer):它和序号字段的值相加表示最后一个紧急数据的下一个字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,也可以称为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。

2.3 TCP连接的建立和关闭

2.3.1 TCP连接的建立

TCP通过“三次握手”来建立连接,握手的过程如下:

(1)客户端发出请求连接报文段,其中报头控制位SYN = 1,初始序号seq = x。客户端进入SYN-SENT(同步已发送)状态。

(2)服务端收到请求报文段后,向客户端发送确认报文段。确认报文段的首部中SYN = 1,ACK =x+ 1,同时为自己选择一个初始序号seq = y。服务端进入SYN-RCVD(同步收到)状态。

(3)客户端收到服务端的确认报文段后,还要向服务端发送一个确认报文段。这个报文段中ACK = 1,确认号ack = y+1, 而自己的序号seq = x+1。这个报文段已经可以携带数据,如果不携带数据则不消耗序列号,而下一个报文段序号仍为seq = x+1;。

至此,TCP连接已经建立,客户端进入ESTABLISHED(已建立连接)状态,当服务端收到确认后,也进入ESTABLISHED(已建立立连接)状态,它们之间便可以正式传递数据了。

2.3.2 TCP关闭连接

TCP连接完成数据的传输后,要进行“四次挥手”,才能关闭连接,挥手的过程如下:

这里写图片描述

(1) 此时 TCP 连接两端都还处于 ESTABLISHED 状态,客户端停止发送数据,并发出一个 FIN 报文段。首部 FIN=1,序号 seq=u(u 等于客户端传输数据最后一字节的序号加 1)。客户端进入 FIN-WAIT-1(终止等待 1)状态。

(2) 服务端回复确认报文段,确认号 ack=u+1,序号 seq=v(v 等于服务端传输数据最后一字节的序号加 1),服务端进入 CLOSE-WAIT(关闭等待)状态。现在 TCP 连接处于半开半闭状态,服务端如果继续发送数据,客户端依然接收。

(3) 客户端收到确认报文,进入 FIN-WAIT-2 状态,服务端发送完数据后,发出 FIN 报文段,FIN=1,确认号 ack=u+1,然后进入 LAST-ACK(最后确认)状态。

(4) 客户端回复确认报文段,ACK=1,确认号 ack=w+1(w 为半开半闭状态时,收到的最后一个字节数据的编号) ,序号 seq=u+1,然后进入 TIME-WAIT(时间等待)状态。
注意此时连接还没有释放,需要时间等待状态结束后(4 分钟) 连接两端才会 CLOSED。设置时间等待是因为,有可能最后一个确认报文丢失而需要重传。

下面来详细分析几个小问题:
服务器通过返回确认报文段使连接进入CLOSE_WAIT状态。其含义就是等待服务器应用程序关闭连接。通常服务器检测到客户端关闭连接后,也会立即给客户端发一个结束报文段来关闭连接。这将使连接转移到LAST_ACK状态,以等待客户端对结束报文段的组后一次确认。一旦确认完成,连接就彻底关闭了。

TIME_WAIT状态存在的原因:
(1)可靠地终止TCP连接;
(2)保证让迟来的TCP报文段有足够的时间被丢弃。
接下来详细分析:
第一个原因很好理解,就不说了。
第二个原因就是说,当一个TCP连接处于TIME_WAIT状态时,我们将无法立即使用占着的端口来建立一个连接。
另外,TCP报文段的最大生存时间是MSL,所以坚持2MSL时间的TIME_WAIT状态能够确认网络上两个传输方向上尚未被接受到的、迟到的TCP报文段都已经消失(被中转路由器丢失)。因此一个连接的新的化身可以在2MSL时间之后安全地建立,而绝不会接收到属于原来连接的应用程序数据。

2.3.3 TCP超时重传

过程如下图所示:

这里写图片描述

TCP模块为每个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动。如果超时时间内未收到对方的应答,TCP模块将重传TCP报文段被重置定时器。linux有两个重要的内核参数与TCP超时重传有关,/proc/sys/net/ipv4/tcp_retries1和/proc/sys/net/ipv4/tcp_retries。前者指定在底层ip接管之前tcp最少执行的重传次数,默认值是3,后者指定在连接放弃前TCP最多可以执行重传的次数,默认值是15.
为了实现超时间重传,需要注意:

1.发送者发送一个报文段后,暂时保存该报文段的副本,为发生超时重传时使用,收到确认报文后删除该报文段。

2.确认报文段也需要序号,才能明确是发出去的那个数据报得到了确认。

3.超时计时器比传输往返时间略长,但具体值是不确定的,根据网络情况而变。


最后,给一张学习TCP协议的脑图,有利于记忆,图片取自:

【net】TCP协议脑图


参考修改:
http://blog.csdn.net/kidck/article/details/51146690

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

一条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.