TCP状态转换示意图如下
针对上面的示意图,主要对以下几点进行解析
- 有哪些进程状态是可以捕捉到的?
- LISTEN、ESTABLISHED、等,其他状态时间很短暂,捕捉不到。
- netstat命令可以捕捉状态。
- 2MSL是什么?
- 2MSL是等待时长,主动关闭连接的一方将会处于TIME_WAIT状态。
- 1MSL大概是30S,处于TIME_WAIT状态的进程(主动断开连接的进程)不会立即终止,而是会等待2MSL的时间;而被动断开连接的一方,在LAST_ACK状态,一旦收到对方的ACK就会立即终止进程。
- 为什么主动断开的一方要等2MSL而被动断开的一方不需要等呢?
- 因为有可能会出现这种情况,主动断开的一方(比如是client)属于TIME_WAIT时,向被断开的一方(比如说server)发送ACK,有可能对方没有收到,这时侯server会再发一次FIN,也就需要client再回复一次ACK(如果client没有等待就终止了,那么server发送的FIN就发送不到了,四次挥手就失败了),所以主动断开连接的一方要等待,来保证正常断开连接,而被断开的一方收到ACK就可以终止进程了,此时连接正常断开。
- 什么是半关闭?
- 如何理解半关闭
- A给B发送FIN(A调用了close函数), 但是B没有给A发送FIN(B没有调用close)
- A断开了与B的连接, B没有断开与A的连接
- 特点:
- A不能给B发送数据, A可以收B发送的数据
- B可以给A发送数据
- 函数: int shutdown(int sockfd, int how);
- sockfd: 要半关闭的一方对应的文件描述符
- 通信的文件描述符
- how:(可以只关读、只关写,或读写都关)
- SHUT_RD - 0 - 读
- SHUT_WR - 1 - 写
- SHUT_RDWR - 2 - 读写
- 使用close()函数能否实现半关闭?
- 不能。使用dup2函数可以复制一个文件描述符fd指向和sfd一样的内容,如果使用close(fd)关闭了对内核缓冲区的读写,但是还存在一个文件描述符sfd可以读写内核缓冲区,也就是说通信依然可以进行,这样并不能实现真正的半关闭。使用shutdown函数可以实现半关闭,是因为shutdown(fd, SHUT_RD)虽然在函数中只对fd关闭了读,但是它实际上是将缓冲区的读给关闭了,所有文件描述符(不管有多少个),都不能再读缓冲区了。
在使用套接字通信时,可以使用netstat命令捕捉进程状态或使用netstat查看网络相关状态信息,netstat的常用参数如下:
- -a (all)显示所有选项,默认不显示LISTEN相关进程,不加-a就不显示LISTEN进程。
- -p 显示建立相关链接的程序名。
- -n 拒绝显示别名,能显示数字的全部转化成数字。
- -t (tcp)仅显示tcp相关选项。
- -u (udp)仅显示udp相关选项。
- -l 仅列出有在 Listen (监听) 的服务状态。