TCP协议具体解释
3.1 TCP服务的特点
TCP协议相对于UDP协议的特点是面向连接、字节流和可靠传输。
使用TCP协议通信的两方必须先建立链接。然后才干開始数据的读写。两方都必须为该链接分配必要的内核资源,以还礼链接状态和连接上数据的传输。TCP链接是全双工的。即两方的数据读写能够通过一个连接进行。完毕数据交换之后,通信两方都必须断开连接以释放系统资源。
TCP协议的这样的连接是一对一的。所以基于广播和多播(目标是多个主机地址)的应用程序不能使用TCP服务。
而无连接协议UDP则很适合于广播和多播。
字节流服务和数据报服务相应到实际编程中的差别体如今通信两方是否必须运行同样次数的读、写操作。当发送端应用程序连续运行多次写操作时。TCP模块先将这些数据放入TCP发送缓冲区中。当TCP模块哦真正開始发送数据时,发送缓冲区中这些等待发送的数据可能被封装成一个或多个TCP报文发出去。
因此,TCP模块发出去的TCP报文段的个数和应用程序运行的写操作次数之间没有固定的数量关系。
当接收端收到一个或多个TCP报文段后,TCP模块将它们携带的应用程序数据依照TCP报文段的序号依次放入TCP接收缓冲区中,并通知应用程序读取数据,接收端应用程序能够一次性将TCP接收缓冲区中的数据所有读出,也能够分多次读取,这取决于用户指定的应用程序读缓冲区的大小。
因此,应用程序运行的读操作次数和TCP模块接收到的TCP报文个数之间也没有固定的数量关系。
综上所述。TCP发送端运行写操作次数和接收端运行读操作次数之间没有不论什么数量关系,这就是字节流的概念:应用程序对数据的发送和接收是没有边界限制的。
UDP则不然,发送端应用程序没运行一次写操作,UDP模块就将其封装成一个UDP数据包并发送之。接收端必须及时针对每个UDP数据报运行读操作。否则就会丢包。而且。假设用户没有指定足够的应用程序缓冲区来读取UDP数据,则UDP数据将被截断。
TCP传输室可靠的。首先,TCP协议採用发送应答机制,即发送端的每一个TCP报文段都必须得到接收方的应答,才觉得这个TCP报文段传输成功。其次,TCP协议採用超市重传机制,发送端在发送一个TCP报文段之后启动定时器。假设在定时时间内未收到应答,它将重发报文段。最后,由于TCP报文段终于是以IP数据报发送的,而IP数据报到达接收端可能乱序、反复,所以TCP协议还会对接收到的TCP报文段重排、整理,再交付给应用层。
TCP头部结构
头部结构
16位port号:告知主机该报文来自哪里(源port)以及传给哪个上层协议或应用程序(目的port)。进行TCP通信时,client通常使用系统自己主动选择的暂时port号。而server则使用知名服务port号。
32位序号:一次TCP通信过程中某一个传输方向上的字节流的每一个字节的编号。如果主机A和主机B进行TCP通信,A发送给B的第一个TCP报文段中。序号值被系统初始化为某个随机值ISN(初始化序号值)。那么在传输方向上,兴许的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。
32位确认好:用作对还有一方发送来的TCP报文段的响应。
其值是收到的TCP报文段的序号值加1.
4位头部长度:标识该TCP头部有多少个32bit(4字节)。
由于4位最大能标识15。所以TCP头部最长是60字节。
6位标识包括例如以下几项:
URG标志,表示紧急指针是否有效
ACK标志。表示确认好是否有效。我们称携带ACK标志的TCP报文段为确认报文段。
PSH标志,提示接收端应用程序应该马上从TCP接收缓冲区中读取数据,为接受兴许数据腾出空间。
RST标志。表示请求对方又一次建立连接。
我们称携带RST标志的TCP报文段为复位报文段。
SYN标志,表示请求建立一个连接。
我们称携带SYN标志的TCP报文段为同步报文段。
FIN标志,表示通知对方本端要关闭连接了。我们称携带FIN标志的TCP报文段为结束报文段。
16位窗体大小:是TCP流量控制的一个手段。
这里说的窗体。指的是接收通知窗体。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据。这样对方就能够控制发送数据的速度。
16位校验和:由发送端填充,接收端对TCP报文段运行CRC算法以校验TCP报文段在传输过程中是否损坏。
16位紧急指针:是一个正的偏移量。它和序号字段值相加表示最后一个紧急数据的下一字节的序号。TCP的紧急指针式发送端向接收端发送紧急数据的方法。
最后一个选项字段是可变长的可选信息,这里不做讨论。
TCP连接的建立和关闭
使用tcpdump观察TCP连接的建立和关闭
这里的測试网络及搭建见
chen123@ubuntu:~$ sudo tcpdump -i eth0 -nt '(src192.168.73.130 and dst 192.168.73.129) or (src 192.168.73.129 and dst192.168.73.130)'
chen123@ubuntu:~$ telnet 192.168.73.130
Trying 192.168.73.130...
Connected to 192.168.73.130.
Escape character is '^]'.
^](回车)#输入ctrl+]并回车
telnet> quit
Connection closed.
在输入tcpdump后的终端会显演示样例如以下内容:
-
IP 192.168.73.129.43999 >192.168.73.130.23: Flags [S], seq 304007584, win 29200, options [mss1460,sackOK,TS val 1129159 ecr 0,nop,wscale 7], length 0
-
IP 192.168.73.130.23 >192.168.73.129.43999: Flags [S.], seq 3646952588, ack 304007585, win 28960,options [mss 1460,sackOK,TS val 1128235 ecr 1129159,nop,wscale 7], length 0
-
IP 192.168.73.129.43999 >192.168.73.130.23: Flags [.], ack 1, win 229, options [nop,nop,TS val 1129160ecr 1128235], length 0
-
IP 192.168.73.129.43999 >192.168.73.130.23: Flags [F.], seq 123, ack 329, win 229, options [nop,nop,TSval 1133956 ecr 1130769], length 0
-
IP 192.168.73.130.23 >192.168.73.129.43999: Flags [F.], seq 329, ack 124, win 227, options[nop,nop,TS val 1133032 ecr 1133956], length 0
-
IP 192.168.73.129.43999 >192.168.73.130.23: Flags [.], ack 330, win 229, options [nop,nop,TS val 1133957ecr 1133032], length 0
下图是TCP连接的建立和关闭时序图
第1个TCP报文段包括SYN标志,因此它是一个同步报文段,即chen123向li123发起请求。
同一时候,该同步报文段包括一个ISN值为304007584的序号。第2个TCP报文段也是同步报文段,表示li123允许与chen123建立连接。
同一时候发送自己的ISN值为3646952588的序号,并对第一个同步进行确认。
确认值为304007585,即第1个同步报文段额序号值加1.前文说过,序号值是用来标识TCP数据流中的每一字节的。
但同步报文比較特殊,即使它并没有携带不论什么应用程序数据,它也要占用一个序号值。第3个TCP报文段是chen123对第2个报文段的确认。但至于为什么ack是1。如有知道者请不吝赐教。至此,TCP连接就建立起来了。建立TCP连接的这3个步骤被称为TCP三次握手。
后面3个TCP报文段是关闭连接的过程。第4个TCP报文段包括FIN标志。因此它是一个结束报文段,即chen123要求关闭连接。结束报文段和同步报文段一样,也要占用一个序号值。li123用报文段5来确认结束该报文段,并发送自己的结束报文段。但有时,这一步会分为两个步骤,即将确认结束报文段和发送自己的结束报文段分为两次发送。报文段6是chen123发送给li123的确认结束报文段。
半关闭状态
TCP连接时全双工的,所以它同意两个方向的传输数据被独立关闭。换言之。通信的一段能够发送结束报文段给对方,告诉它本端已经完毕了数据的发送,但同意继续接收来自对方的数据。直到对方也发送结束报文段以关闭连接。TCP连接的这样的状态成为半关闭状态。
连接超时
假设client訪问一个距离它非常远的server,或者因为网络繁忙,导致server对client发送出的同步报文段没有应答,此时对于提供可靠服务的TCP来说,它必定先进行重连,假设仍然无效。则通知应用程序连接超时。
为了观察连接超时,在chen123上运行以下的操作:
chen123@ubuntu:~$ sudo iptables –F
chen123@ubuntu:~$ sudo iptables -I INPUT -p tcp --syn-i eth0 -j DROP
在li123运行telnet难过了 chen123。并用tcpdump抓取这个过程中TCP报文段,例如以下操作:
li123@ubuntu:~$sudo tcpdump -n -i eth0 port 23
li123@ubuntu:/$date; telnet 192.168.73.129; date
在输入telnet的终端输出例如以下:
Thu Jun 2604:06:27 PDT 2014
Trying192.168.73.129...
telnet: Unableto connect to remote host: Connection timed out
Thu Jun 2604:08:34 PDT 2014
从两次date命令等输出来看。li123建立TCP连接的超时时间是127s。
本次tcpdump的输出例如以下:
04:06:27.638626IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3877349 ecr 0,nop,wscale 7], length 0
04:06:28.638036 IP192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3877599 ecr 0,nop,wscale 7], length 0
04:06:30.643072IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3878100 ecr 0,nop,wscale 7], length 0
04:06:34.650500IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3879102 ecr 0,nop,wscale 7], length 0
04:06:42.658032IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3881104 ecr 0,nop,wscale 7], length 0
04:06:58.690290IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3885112 ecr 0,nop,wscale 7], length 0
04:07:30.722385IP 192.168.73.130.56817 > 192.168.73.129.23: Flags [S], seq 205703381, win29200, options [mss 1460,sackOK,TS val 3893120 ecr 0,nop,wscale 7], length 0
我们一共抓取了7个TCP报文段。他们都是同步报文段,而且具有对应的序号值,这说明后面5个同步报文段都是超时重发报文段。观察这些TCP报文段被发送的时间间隔,他们各自是1s、2s、4s、8s、16s和32s。
因此TCP一共运行了6次重连重连操作,这是由/proc/sys/net/ipv4/tcp_syn_retries内核变量所定义的,每次重连的超时时间都添加了一倍。
在6次重连均失败的情况下,TCP模块放弃连接并通知应用程序。