学习视频链接
黑马程序员-Linux网络编程_哔哩哔哩_bilibili黑马程序员黑马程序员-Linux网络编程, 视频播放量 241433、弹幕量 7600、点赞数 1627、投硬币枚数 744、收藏人数 9498、转发人数 588, 视频作者 可爱的小飞猪, 作者简介 腹有诗书气自华,相关视频:linux全套教程【黑马】,黑马程序员-Linux系统编程,超细超强Linux网络编程,【黑马程序员】B站讲的最透彻的Jenkins教程,太厉害了 已跪!终于有人能把Jenkins讲的明明白白了(持续集成工具Jenkins),C++项目实战,C/C++开源项目推荐,帮助大家从学习走向实践!研究开源项目是获得项目经验的绝好途径!,每个程序员必看的TCP/IP协议、socket通信、IO、Linux操作系统,这里全有~,最快Linux入门教程+最新学习路线!程序员必备组合拳,千锋教育嵌入式物联网教程800集,C语言编程入门到精通(物联网开发工程师必备视频),【并发】IO多路复用select/poll/epoll介绍https://www.bilibili.com/video/BV1iJ411S7UA?p=45&spm_id_from=333.1007.top_right_bar_window_history.content.click
目录
一、TCP状态转移图
1.1 总览
1.2 分析三次握手主动端
1.3 分析四次挥手主动端
1.4 被动端
1.5 所有状态简介
二、2MSL和端口复用
2.1 2MSL
2.2 端口复用
三、半关闭
一开始服务端和客户端都是 CLOSE 的状态。客户端是主动方发送 SYN 消息,服务端是被动方接收到 SYN 消息,客户端发完 SYN 消息后变成 SYN_SEND 状态。服务端 ACK 消息应答客户端的 SYN,同时把自己的 SYN 发送过去。客户端接收到 SYN 和 ACK,发送应答 SYN 消息的 ACK 消息。发送完 ACK 消息,客户端的状态就变成了 ESTACLISHED
使用程序分析上述过程:
右上角的窗口中查询相应的端口号,发现三个 TCP
第一个 TCP 是服务器用于监听的,处于 LISTEN 状态
第二个 TCP 是用于通信的服务器,处于 ESTACLISHED 状态
第三个 TCP 是用于通信的客户端,处于 ESTACLISHED 状态
一开始主动提出关闭连接方和被动方都是 ESTACLISHED 状态,主动提出关闭连接的一端在左边,主动方发送 FIN,发送完消息后主动方变成 FIN_WAIT_1 状态。被动方同意的话会回信 ACK,主动方收到信息 ACK 后变成 FIN_WAIT_2 状态 (也就是半关闭状态)
然后被动方发送 FIN 给主动方,主动方收到后发送 ACK。主动方发完 ACK 消息后,主动方的状态变成 TIME_WAIT 状态。TIME_WAIT 状态不会立即变成 CLOSE,要经历 2MSL 时长才会变成 CLOSE 状态 (MSL 是最长报文生存时间,2MSL 大约四十秒)
下图中,客户端就是处于等待的状态
CLOSED:表示初始状态。
LISTEN:该状态表示服务器端的某个SOCKET处于监听状态,可以接受连接。
SYN_SENT:这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,随即进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
SYN_RCVD: 该状态表示接收到SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂。此种状态时,当收到客户端的ACK报文后,会进入到ESTABLISHED状态。
ESTABLISHED:表示连接已经建立。
FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。区别是:
FIN_WAIT_1状态是当socket在ESTABLISHED状态时,想主动关闭连接,向对方发送了FIN报文,此时该socket进入到FIN_WAIT_1状态。
FIN_WAIT_2状态是当对方回应ACK后,该socket进入到FIN_WAIT_2状态,正常情况下,对方应马上回应ACK报文,所以FIN_WAIT_1状态一般较难见到,而FIN_WAIT_2状态可用netstat看到。
FIN_WAIT_2:主动关闭链接的一方,发出FIN收到ACK以后进入该状态。称之为半连接或半关闭状态。该状态下的socket只能接收数据,不能发。
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,等2MSL后即可回到CLOSED可用状态。如果FIN_WAIT_1状态下,收到对方同时带 FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这种状态较特殊,属于一种较罕见的状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 此种状态表示在等待关闭。当对方关闭一个SOCKET后发送FIN报文给自己,系统会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,察看是否还有数据发送给对方,如果没有可以 close这个SOCKET,发送FIN报文给对方,即关闭连接。所以在CLOSE_WAIT状态下,需要关闭连接。
LAST_ACK: 该状态是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,即可以进入到CLOSED可用状态。
为保证最后一个 ACK 能成功被对端接收。(等待期间,对端没收到我发的 ACK,对端会再次发送 FIN 请求)
但是面临的问题是服务端关闭后短期内不能再启动了。因为要等 2MSL 时长,在此期间端口是被占用了,端口是写死的,所以不能启动
因为有 2MSL 时长,所以有端口复用这一概念。我们现在可以设置无需等待直接复用这个端口,需要使用以下函数
int opt = 1; // 设置端口复用
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (* void)&opt, sizeof(opt));
通信双方中,只有一端关闭通信 —— FIN_WAIT_2
可以使用的函数:close(cfd)、shutdown(int fd, int how);
how: SHUT_RD 关闭读端;SHUT_WR 关闭写端;SHUT_RDWR 关闭读写端
close 和 shutdown 的区别
close 是文件描述符减 1
shutdown 是文件描述符 全部关闭