TCP协议--TCP连接的建立和关闭

《Linux高性能服务器编程》阅读笔记:

  TCP连接的建立和关闭,也就是常说的三次握手和四次挥手,其模型可以示意为:
这里写图片描述

  我们可以利用tcpdump命令观察这个两个过程。

机器1(telnet服务器):Ubuntu14.04 IP地址为192.168.239.136
机器2(telnet客户端):Ubuntu11.04 IP地址为192.168.239.149

  在Ubuntu14.04机器(telnet客户端)中登录Ubuntu11.04的telnet服务器:

$ sudo tcpdump -i eth0 -nt '(src 192.168.239.136 and dst 192.168.239.149) or (src 192.168.239.149 and dst 192.168.239.136)' -S
$ telnet 192.168.239.149       #在另一终端运行
Trying 192.168.239.149...
Connected to 192.168.239.149.
Escape character is '^]'.
Ubuntu 11.04
kingsine-virtual-machine login: 
telnet> quit                    #退出telnet服务
Connection closed.
iter@iter-virtual-machine:~$ 

1. TCP的连接的建立

  过程中tcpdump抓取到的最开始的3个数据包,即为TCP建立连接的三次握手:

IP 192.168.239.136.41736 > 192.168.239.149.23: Flags [S], seq 1930808739, win 29200, options [mss 1460,sackOK,TS val 5576903 ecr 0,nop,wscale 7], length 0
IP 192.168.239.149.23 > 192.168.239.136.41736: Flags [S.], seq 160797553, ack 1930808740, win 14480, options [mss 1460,sackOK,TS val 9091274 ecr 5576903,nop,wscale 6], length 0
IP 192.168.239.136.41736 > 192.168.239.149.23: Flags [.], ack 160797554, win 229, options [nop,nop,TS val 5576907 ecr 9091274], length 0

  对应上图,连接时的示意为:
这里写图片描述

  (1) 第1个TCP报文包含SYN标志,因此它是一个同步报文段,即ubuntu14.04机器向ubuntu11.04机器发出连接请求,同时同步报文段包含一个ISN值为1930808739的序号(seq)
  (2) 第2个TCP报文段同样是一个同步报文段,表示ubuntu11.04机器同意与ubuntu14.04建立TCP连接,同时它发送自己的ISN值为160797553的序号,并对第1个同步报文段进行确认,确认值为1930808740,即第一个同步报文段的序号值加1。

  在TCP协议–TCP头部 一文中,提到32位的序号值是用来标识TCP数据流中的数据报文的起始字节位于整个要发送的字节流的序号值的,但是同步报文段比较特殊,即使它没有携带任何应用程序数据,也占用一个序号值

  (3) 第3个TCP报文段是ubuntu14.04机器对第2个同步报文段的确认。至此TCP连接就建立完成。

  这里有2个疑问需要解释:
  ①第3步骤看似没有必要,为什么要将TCP连接的建立放在第3步骤之后?
  假设到步骤2就建立起TCP连接,那么服务器为该连接创建的资源就会进入等待与客户端的交互中,但是若客户端在发出SYN报文之后由于某种原因并没有收到或者间隔太久才收到服务器的回复SYN报文,客户端以为请求连接失败,并退出。而服务器在发完自身的SYN报文后陷入等到已离线的客户端的交互,显然这会造成服务器资源的浪费,所以建立TCP连接需要三次握手,即需要三个步骤。

  ②在Linux的tcpdump命令抓取TCP数据报时候,若没有加上-S命令选项,步骤三的序号值为1,这显然不符合确认值的规范,为什么?
  因为网络解析协议软件(如tcpdump)有一个宗旨,让协议分析结果尽量简单直白。tcpdump将步骤3的序号设置偏移值,即相对于初始序列号的偏移值。在不加入-S的选项情况下,tcpdump输出的序号值和确认值从第3个TCP报文段开始就都是相对于初始ISN的偏移。

2. TCP连接的关闭和半关闭状态

  tcp抓到数据包中的最后3个为连接关闭数据包(这显然比前面讲的4次挥手少了一个数据包)

IP 192.168.239.136.41736 > 192.168.239.149.23: Flags [F.], seq 1930808875, ack 160797657, win 229, options [nop,nop,TS val 5577989 ecr 9091296], length 0
IP 192.168.239.149.23 > 192.168.239.136.41736: Flags [F.], seq 160797657, ack 1930808876, win 227, options [nop,nop,TS val 9092361 ecr 5577989], length 0
IP 192.168.239.136.41736 > 192.168.239.149.23: Flags [.], ack 160797658, win 229, options [nop,nop,TS val 5577991 ecr 9092361], length 0

  对应如下图:
这里写图片描述

  (1) 第1个TCP报文段包含FIN标志,它是一个结束报文段,即ubuntu14.04机器要求关闭连接。结束报文段和同步报文段一样,也要占用一个序号值。
  (2) 第2个TCP报文段应该是ubuntu11.04发送确认该结束报文段,但是通过tcpdump抓取到的数据包发现并没有此现象。这是因为:
  在TCP连接过程中,一接收到对方的结束报文时,本端在发送确认包前有一段延时(不延时直接确认显然有点草率),如果自己在这段时间内刚好有数据发送,就跟着确认包发送,如果没有则确认包单独发送。在这里确认报被第3个数据结束报文合并发送了。这个称为延迟确认,一般发生在服务端,因为服务端的处理请求速度快。客户端由于数据是用户输入的,会慢很多,所以确认报文段一般被单独发送。
  (3) 第3个报文段是ubuntu11.04发送自己的结束报文
  (4) 第4个报文时ubuntu14.04对结束报文的确认

  一般来说,TCP连接是由客户端发起,通过三次握手建立连接。TCP连接的关闭相对复杂写,可以是客户端执行主动关闭,如上例子,也可以是服务器主动执行关闭,还可以是同时关闭。

  TCP连接是全双工的,它允许两个方向的数据被独立关闭。即通信的一端可以发送结束报文段给对方,告诉对方本端已完成数据的发送,但是允许继续接收来自对方的的数据,知道对方也发送结束报文以关闭连接。这种TCP连接状态称为半关闭状态,socket网络编程时通过shutdown()函数实现半关闭的。服务器和客户端应用程序判断对方是否关闭连接(对方处于半连接)的一般方法是判断read()系统调用是否返回0

3. 连接超时

  倘若客户端访问一个远距离的服务器或者由于网络繁忙,导致服务器对于客户端发送出的同步报文段没有应答时,作为提供的是可靠服务的TCP连接来说,它首先要进行重连,可能执行多次重连,若重连多次后仍然无效则通知应用程序连接超时。

  Linux的iptable命令可用于过滤数据报,在这里可以利用它来丢弃所有接收到的连请求,即丢弃所有同步报文段,这样客户端就无法得到确认报文,造成服务器繁忙的假象。在ubuntu11.04(telnet服务器)中运行如下命令:

$ sudo iptables -F
$ sudo iptables -I INPUT -p tcp --syn -i eth0 -j DROP

  在ubuntu14.04中登录telnet服务器并用telnet抓取过程产生的数据包:

$ sudo tcpdump -n -i eth0 port 23 -S
$ date; telnet 192.168.239.149; date   #在另一终端执行,前后的date命令方便查看中间消耗的时间

  tcpdump抓取到的数据包有7个,如下:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:44:57.770522 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7929076 ecr 0,nop,wscale 7], length 0
16:44:58.769121 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7929326 ecr 0,nop,wscale 7], length 0
16:45:00.774127 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7929827 ecr 0,nop,wscale 7], length 0
16:45:04.777163 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7930828 ecr 0,nop,wscale 7], length 0
16:45:12.792472 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7932832 ecr 0,nop,wscale 7], length 0
16:45:28.825423 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7936840 ecr 0,nop,wscale 7], length 0
16:46:00.920398 IP 192.168.239.136.36632 > 192.168.239.149.23: Flags [S], seq 3968412248, win 29200, options [mss 1460,sackOK,TS val 7944864 ecr 0,nop,wscale 7], length 0

  它们都是同步报文段,具有相同的序号值,说明后面5个同步报文段都是超时重连报文段。观察这些报文段被发送的时间间隔,分别为1s、2s、4s、8s、16s和32s,,可以推断最后一个重连数据报的时间间隔为64s。TCP模块一共执行6次重连操作,这是由cat /proc/sys/net/ipv4/tcp_syn_retries决定的:
这里写图片描述

  在6次重连失败后,TCP模块将放弃连接并通知应用程序。在应用程序中我们可以修改连接的超时时间,具体方法在书中后续有介绍。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值