1 图示
粗实线代表主动端,虚线表示被动方,细实线表示一些其他状态。
可以通过 netstat -apn | grpe 端口号 查看服务器/客户端的状态。
2 状态转换分析
-
主动发起连接请求端:CLOSE – 发送SYN – SEND_SYN – 接收ACK、SYN – 发送ACK – ESTABLISHED(数据通信状态)
-
主动关闭连接请求端:ESTABLISHED(数据通信状态) – 发送FIN – FIN_WAIT_1 – 接收ACK – FIN_WAIT_2(半关闭) – 回发ACK – TIME_WAIT(只有主动关闭连接方会经历该状态) – 等待2MSL时长 – CLOSE
-
被动接收连接请求端:CLOSE – LISTEN – 接收SYN – LISTEN – 发送ACK、SYN – SYN_RCVD – 接收ACK – ESTABLISHED(数据通信状态)
-
被动关闭连接请求端:ESTABLISHED(数据通信状态) – 接收FIN – ESTABLISHED(数据通信状态) – 发送ACK – CLOSE_WAIT(说明对端【主动关闭连接端】处于半关闭) – 发送FIN – LAST_ACK --接收ACK – CLOSE
2MSL时长:
一定出现在【主动关闭连接请求端】。----- TIME_WAIT
保证最后一个ACK能够成功被对端接收。(等待期间,对端没有收到我发送的ACK,对端会再发送FIN请求)
3 设置端口复用
在绑定地址结构前(server代码的socket()和bind()调用之间)插入
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// setsockopt其他选项可以查看UNP(UNIX网络编程)这本书。
4 半关闭函数
#include <sys/socket.h>
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。
*/
close函数与shutdown函数
使用close中止一个连接,但它只是减少描述符的引用计数,并不直接关闭连接,只有当描述符的引用计数为0时才关闭连接。
shutdown不考虑描述符的引用计数,直接关闭描述符。也可选择中止一个方向的连接,只中止读或只中止写。
注意:
- 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
- 在多进程中如果一个进程调用了shutdown(sfd, SHUT_RDWR)后,其它的进程将无法进行通信。但,如果一个进程close(sfd)将不会影响到其它进程。