UNP-TCP关闭连接要优雅吗

TCP关闭连接

我们知道发起关闭连接的一方会有一段时间处于TIME_WAIT状态。那么UNP如何发起关闭连接?

我们知道,一个 TCP 连接需要经过三次握手进入数据传输阶段,最后来到连接关闭阶段。在最后的连接关闭阶段,我们需要重点关注的是“半连接”状态。因为 TCP 是双向的,这里说的方向,指的是数据流的写入 - 读出的方向。

举个例子,客户端主动发起连接的中断,将自己到服务器端的数据流方向关闭,此时,客户端不再往服务器端写入数据,服务器端读完客户端数据后就不会再有新的报文到达。但这并不意味着,TCP 连接已经完全关闭,很有可能的是,服务器端正在对客户端的最后报文进行处理,比如去访问数据库,存入一些数据;或者是计算出某个客户端需要的值,当完成这些操作之后,服务器端把结果通过套接字写给客户端,我们说这个套接字的状态此时是“半关闭”的。最后,服务器端才有条不紊地关闭剩下的半个连接,结束这一段 TCP 连接的使命。

这里的服务器关闭连接,就很优雅

关闭连接的方式

close


int close(int sockfd)

这个函数会对套接字引用计数减一,一旦发现套接字引用计数到 0,就会对套接字进行彻底释放,并且会关闭 TCP 两个方向的数据流。

套接字引用计数是什么意思呢?因为套接字可以被多个进程共享,你可以理解为我们给每个套接字都设置了一个积分,如果我们通过 fork 的方式产生子进程,套接字就会积分 +1, 如果我们调用一次 close 函数,套接字积分就会 -1。这就是套接字引用计数的含义。

注意到一个问题,close并不能关闭一个方向,TCP提出的解决方案为shutdown函数。

shutdown

/*
SHUT_RD(0):关闭连接的“读”这个方向,对该套接字进行读操作直接返回 EOF。从数据角度来看,套接字上接收缓冲区已有的数据将被丢弃,如果再有新的数据流到达,会对数据进行 ACK,然后悄悄地丢弃。也就是说,对端还是会接收到 ACK,在这种情况下根本不知道数据已经被丢弃了
SHUT_WR(1):关闭连接的“写”这个方向,这就是常被称为”半关闭“的连接。此时,不管套接字引用计数的值是多少,都会直接关闭连接的写方向。套接字上发送缓冲区已有的数据将被立即发送出去,并发送一个 FIN 报文给对端。应用程序如果对该套接字进行写操作会报错。

SHUT_RDWR(2):相当于 SHUT_RD 和 SHUT_WR 操作各一次,关闭套接字的读和写两个方向。
*/
int shutdown(int sockfd, int howto)

close与shutdown的区别

  1. close会关闭连接并释放资源。而shutdown不会释放资源
  2. close存在引用计数的概念,不一定导致该套接字不可用。shutdown不管引用计数,直接使该套接字不可用(不可读或者不可写)。
  3. close的引用计数导致不一定发出FIN结束报文,shutdown总会发出。

在期望关闭一个方向时,应该使用shutdown

posted @ 2020-04-26 20:37  傻蜗牛  阅读(236)  评论(0)    收藏  举报