TCP状态转换逻辑

1、客户端(主动)

  • close —> syn_sent —> established —> fin_wait1 —> fin_wait2 —> time_wait —> 2(msl)
  • close —> syn_sent —> established —> fin_wait1 —> closing —> time_wait —> 2(msl)
  • close —> syn_sent —> established —> fin_wait1 —> time_wait —> 2(msl)
    • msl:maximum segment lifetime

2、服务端(被动)

  • close —> listen —> syn_rcvd —> established —> close_wait —> last_ack —> close
  • close —> listen —> syn_rcvd —(RST)—> listen

  • 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可用状态。

3、在Server—->Client通讯环境中,结束Client进程

  • FIN_WAIT1状态时间很短,后续接收报文不同,状态转变也不一样
    • FIN_WAIT1 —(ACK)–> FIN_WAIT2 —(FIN)–> TIME_WAIT —(ACK)–>2(MSL)
    • FIN_WAIT1 —(FIN)–> CLOSING —(ACK)–> TIME-WAIT —(ACK)–>2(MSL)
    • FIN_WAIT1 —(ACK+FIN)–> TIME_WAITGG —(ACK)–>2(MSL)

4、在Server—->Client通讯环境中,结束Server进程

  • Server进程结束前发送FIN报文,通讯状态由ESTABLISHED ——> FIN_WAIT1
  • Client收到FIN报文后,状态由ESTABLISHED ——> CLOSE_WAIT,回复ACK报文
  • Server收到ACK报文后,状态由FIN_WAIT1 ——> FIN_WAIT2

5、shutdown函数

  • 相比close函数
    • 可以只关闭读(SHUT_RD)、写(SHUT_WR)或读写(SHUT_RDWR)的操作;
    • 不考虑文件描述符的引用计数,直接关闭文件描述符。
#include <sys/socket.h>

int shutdown(int sockfd, int how);

DESCRIPTION
       The  shutdown()  call causes all or part of a full-duplex connection on the socket associated with sockfd to be shut down.  If how is SHUT_RD, further receptions will be disallowed.  If how is SHUT_WR, further transmissions will be disallowed.  If how  is  SHUT_RDWR,  further  receptions  and transmissions will be disallowed.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

6、setsockopt函数

  • 为解决端口复用的问题,可以使用setsockopt函数
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

e.g

int optval = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

Leave a Reply