网络编程3.5:理解TCP状态时序图

返回:Linux网络编程学习笔记

TCP状态时序图如下:

1. 三次握手(创建连接)

TCP建立连接时,三次握手时序如下:TCP数据报格式:

第一次握手:SYN, 1000(0), <mss 1460>                         

//控制位SYN置1,32位序列号为1000,该段不携带有效载荷(数据字节数为0),mss(Maximum Segment Size,最大报文长度)选项值为1460;

第二次握手:SYN, 8000(0), ACK 1001, <mss 1024>       

//控制位SYN置1,32位序列号为8000,该段不携带有效载荷,ACK置1,32位确认序列号为1001(代表client端1001之前的包,server端都收到了),mss选项值为1024;

第三次握手:ACK, 8001                                                   

//控制位ACK置1,32位确认序列号为8001(代表server端8001之前的包,client端都收到了)。

三次握手发生在内核空间,用户层的主要体现是,connect()和accept()在两端生成网络连接套接字。

使用命令查看端口状态:netstat -apn|grep 9527

root@wang-virtual-machine:/home/wang/nfs# netstat -apn|grep 9527
tcp        0      0 0.0.0.0:9527            0.0.0.0:*               LISTEN      4087/./service
tcp        0      0 127.0.0.1:9527          127.0.0.1:47286         ESTABLISHED 4087/./service
tcp        0      0 127.0.0.1:47286         127.0.0.1:9527          ESTABLISHED 4088/nc

主动发起连接请求端:    CLOSE -- 发送SYN -- SEND_SYN -- 接收 ACK、SYN -- SEND_SYN -- 发送 ACK -- ESTABLISHED(数据通信态)

被动接收连接请求端: CLOSE -- LISTEN -- 接收 SYN -- LISTEN -- 发送 ACK、SYN -- SYN_RCVD -- 接收ACK -- ESTABLISHED(数据通信态)

主动发起连接                                                  被动接受连接

2. 数据传输与滑动窗口

滑动窗口:允许多发单回或多收单确认

第1至第3为建立连接阶段,sender端的滑动窗口缓冲区大小为4k,receiver端滑动窗口的缓冲区大小为6k字节;

第4至第9步,sender向receiver端发送了6次1k的数据;

第10至11步,receiver端告诉sender,缓冲区2k的数据已经处理掉了,空闲大小为4k。

第12至13步,sender向receiver再发2k的数据,并关闭了发送(半关闭);

第14至15步,为ACK应答;

第17步:receive端关闭了发送;

第18步:sender端回复了receive端关闭。

3.四次握手(关闭连接)

主动关闭连接请求端: ESTABLISHED(数据通信态) -- 发送 FIN -- FIN_WAIT_1 -- 接收ACK -- FIN_WAIT_2(半关闭)

                -- 接收对端发送 FIN -- FIN_WAIT_2(半关闭)-- 回发ACK -- TIME_WAIT(只有主动关闭连接方,会经历该状态)

                -- 等 2MSL时长 -- CLOSE 

被动关闭连接请求端: ESTABLISHED(数据通信态) -- 接收 FIN -- ESTABLISHED(数据通信态) -- 发送ACK 

                -- CLOSE_WAIT (说明对端【主动关闭连接端】处于半关闭状态) -- 发送FIN -- LAST_ACK -- 接收ACK -- CLOSE

主动发起关闭                                                   被动接受关闭

client与server建立TCP socket连接后,如果client端主动关闭连接,会进入FIN_WAIT2状态

root@wang-virtual-machine:/home/wang/nfs# netstat -apn|grep 9527
tcp        0      0 0.0.0.0:9527            0.0.0.0:*               LISTEN      4087/./service
tcp        0      0 127.0.0.1:9527          127.0.0.1:47286         CLOSE_WAIT  4087/./service
tcp        0      0 127.0.0.1:47286         127.0.0.1:9527          FIN_WAIT2   -

如果server端主动关闭,其状态会从上方的CLOSE_WAIT变为FIN_WAIT2状态

root@wang-virtual-machine:/home/wang/nfs# netstat -apn|grep 9527
tcp        0      0 127.0.0.1:9527          127.0.0.1:47288         FIN_WAIT2   -
tcp        0      0 127.0.0.1:47288         127.0.0.1:9527          CLOSE_WAIT  4143/nc

在server端主动关闭的情况下,立马重启server端,会出现以下报错信息,主要原因是FIN_WAIT2状态会持续40s,9527这个端口还在被占用。

root@wang-virtual-machine:/home/wang/nfs# ./service
error bind!
: Address already in use

 在server的TCP连接没有完全断开之前不允许重新监听是不合理的。因为,TCP连接没有完全断开指的是connfd(127.0.0.1:47288)没有完全断开,而我们重新监听的是lis-tenfd(0.0.0.0:9527),虽然是占用同一个端口,但IP地址不同,connfd对应的是与某个客户端通讯的一个具体的IP地址,而listenfd对应的是wildcard address。解决这个问题的方法是使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符。
        在server代码的socket()和bind()调用之间插入如下代码:

    int opt = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

有关setsockopt可以设置的其它选项请参考UNP第7章。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

snaking616

你的鼓励是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值