c语言 socket 断开自动连接,如何优雅地断开TCP连接?

socket关闭: close()和shutdown()的差异

对于一个tcp连接,在c语言里一般有2种方法可以将其关闭:

close(sock_fd);

或者

shutdown(sock_fd, ...);

多数情况下这2个方法的效果没有区别,可以互换使用。除了:

close() 是针对file的操作

shutdown() 是针对socket的操作

nix系统里socket是1个文件,但文件不1定是1个socket;

所以在进入系统调用后和达到协议层前(发出FIN包这一段), close()和shutdown()的行为会有1点差异。

到达协议层以后,close()和shutdown()没有区别。

举几个栗子示范下close()和shutdown()的差异

下面通过几个例子演示下close()和shutdown()在多线程并发时的行为差异, 我们假设场景是:

sock_fd 是一个blocking mode的socket。

thread-1 正在对sock_fd进行阻塞的recv(),还没有返回。

thread-2 直接对sock_fd调用close() 或 shutdown()。

不考虑linger。

栗子1: socket阻塞在recv()上, 调用close()

// Close a waiting recv()

Time

|

| thread-1 | thread-2 | tcpdump

| | |

| recv(sock_fd | |

| | |

1| | close(sock_fd) = 0 |

| | | // Some data arrived

| | | // after close()

2| | | < seq 1:36 ... length 35

| | | > ack 36 ...

| // Data was received. | |

3| <... recv resumed>) = 35 | |

4| | | > FIN sent

| | | < ack of FIN received

| | | ...

| // Can't be used any more | |

5v recv(sock_fd)= -1 | |

在上面的例子里:

(1) thread-2 调用close()立即成功返回,这时recv()还在使用sock_fd。

这里因为有另外1个线程thread-1正在使用sock_fd, 所以只是标记这个sock_fd为要关闭的。 socket并没有真正关闭。

这时recv()还继续处于阻塞读取状态。

(2) close()之后,有些数据到了,recv可以读取并返回了。

(3) recv()收到数据, 正确退出。

(4) rece()结束调用,释放socket的引用,这时底层开始关闭socket的流程。

(5) 再次调用recv()就会得到错误。

可以看到,close()没有立即关闭socket的连接,也没有打断等待的recv()。

栗子2: socket阻塞在recv()上, 调用shutdown()

// Shutdown a waiting recv()

Time

|

| thread-1 | thread-2 | tcpdump

| | |

| recv(sock_fd | |

| | |

1| | shutdown(sock_fd) = 0 | > FIN sent

| | | < ack of FIN received

| | | ...

| // Woken up by shutdown() | |

| // no errno set | |

2| <... recv resumed>) = 0 | |

v | |

在上面的例子里:

(1) thread-1还在等待sock_fd, thread-2调用shutdown(), 立即开始关闭socket的流程,发FIN 包等。

然后, 内核中tcp_shutdown中会调用sock_def_wakeup 唤醒阻塞在recv()上的thread-1。

(2) 这时recv()阻塞的线程被唤醒等待并立即返回。 返回码是0,表示socket已经关了。

可以看到,shutdown()和close()不同, 会立即关闭socket的连接,并唤醒等待的recv()。

以上2个例子的代码

close-or-shutdown-recv

栗子3: socket阻塞在accept()上, 调用shutdown()

类似的,对阻塞在accept()上的socket调用shutdown(),accept也会被唤醒:

// Shutdown a waiting accept()

Time

|

| thread-1 | thread-2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值