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

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

TCP状态时序图如下:

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

TCP建立连接时,三次握手时序如下: TCP数据报格式:
网络编程3.5:理解TCP状态时序图_第1张图片

第一次握手:SYN, 1000(0),                          

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

第二次握手:SYN, 8000(0), ACK 1001,        

//控制位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(数据通信态)

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

网络编程3.5:理解TCP状态时序图_第2张图片

网络编程3.5:理解TCP状态时序图_第3张图片

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.5:理解TCP状态时序图_第4张图片

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

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

网络编程3.5:理解TCP状态时序图_第5张图片

网络编程3.5:理解TCP状态时序图_第6张图片

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章。

你可能感兴趣的:(linux网络编程,TCP)