写在前面:
Linux 网络编程 全解(一)--------网络基础协议
Linux 网络编程 全解(二)--------套接字socket
Linux 网络编程 全解(三)--------TCP三次握手、数据传输、四次挥手、滑动窗口
Linux 网络编程 全解(四)--------多进程并发服务器和多线程并发服务器
正文:
一、TCP状态切换
先贴一张TCP的状态转换图,如下:
图中:实线部分为主动发起的,虚线部分为被动相应的。
1、先来看主动发起连接请求(一般是client)的状态变化:
发送SYN 接受对端的SYN+ACK,并发送给对端ACK
有原来的close态 -------------------------->成为SYN_SENT态--------------------------------------------------------------------------->成为
ESTABLISHED态,即数据通信态。
2、主动关闭连接请求状态变化:
发送FIN标志 对端回复ACK之后
原来为ESTABLISHED--------------------------->成为FIN_WAIT_1态--------------------------->成为FIN_WAIT_2
收到对端的FIN并给对端发送ACK之后 等待2MSL时长之后
态(FIN_WAIT_2就是半关闭状态)-------------------------------------------------------->成为TIME_WAIT态---------------------------------------
------>重新回到 close态
注意:只有主动关闭连接方才会经历TIME_WAIT状态,才会经历TIME_WAIT之后的等待2MSL时长的状态。
2MSL TIME_WAIT存在的意义:让 4 次握手关闭流程更加可靠; 4 次握手的最后一个 ACK 是是由主动关闭方发送出去的,若这个 ACK 丢失,被动关闭方会再次发一个 FIN 过来。若主动关闭方能够保持一个 2MSL 的 TIME_WAIT 状态,则有更大的机会让
丢失的 ACK 被再次发送出去。 RFC(Request For Comments) 793 中规定 MSL 为 2 分钟,实际应用中常用的是 30 秒, 1 分钟和 2 分钟等
3、被动接受连接(一般是server)
一起来就成为 接收到对端的SYN并发送SYN+ACK之后 对端回复ACK之后
有原来的close态----------------------->listen态------------------------------------------------->成为SYN_RCVD态----------------------->成
为ESTABLISHED态
4、被动关闭连接
对端发送FIN标志,并给对端回复ACK之后 给对端发送FIN标志之后
原来为ESTABLISHED------------------------------------------>成为CLOSE_WAIT状态(说明对端已经进入半关闭状态)----------------->
接受到对端的ACK之后
成为LAST_ACK状态--------------------------------->成为close状态
二、其他的几个 补充点:
1、端口复用函数
在 server 代码的 socket()和 bind()调用之间插入如下代码
int opt = 1;// 1:设置端口复用,0:设置端口不复用
int setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,&opt, sizeof(opt));
2、shutdown函数
int shutdown(int sockfd, int how);
sockfd: 需要关闭的 socket 的描述符
how: 允许为 shutdown 操作选择以下几种方式:
SHUT_RD(0): 关闭 sockfd 上的读功能,此选项将不允许 sockfd 进行读操作。
该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被无声的丢弃掉。
SHUT_WR(1): 关闭 sockfd 的写功能,此选项将不允许 sockfd 进行写操作。 进程不能在对此套接字发出写操作。
SHUT_RDWR(2): 关闭 sockfd 的读写功能。 相当于调用 shutdown 两次:首先是以 SHUT_RD,然后以 SHUT_WR