http://blog.csdn.net/Solstice/article/details/6208634

今天收到一位网友来信:

在 simple 中的 daytime 示例中,服务端主动关闭时调用的是如下函数序列,这不是只是关闭了连接上的写操作吗,怎么是关闭了整个连接?

1: void DaytimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
2: {
3: if (conn->connected())
4: {
5: conn->send(Timestamp::now().toFormattedString() + "/n");
6: conn->shutdown();
7: }
8: }
9:
10: void TcpConnection::shutdown()
11: {
12: if (state_ == kConnected)
13: {
14: setState(kDisconnecting);
15: loop_->runInLoop(boost::bind(&TcpConnection::shutdownInLoop, this));
16: }
17: }
18:
19: void TcpConnection::shutdownInLoop()
20: {
21: loop_->assertInLoopThread();
22: if (!channel_->isWriting())
23: {
24: // we are not writing
25: socket_->shutdownWrite();
26: }
27: }
28:
29: void Socket::shutdownWrite()
30: {
31: sockets::shutdownWrite(sockfd_);
32: }
33:
34: void sockets::shutdownWrite(int sockfd)
35: {
36: if (::shutdown(sockfd, SHUT_WR) < 0)
37: {
38: LOG_SYSERR << "sockets::shutdownWrite";
39: }
40: }

  

陈硕答复如下:

Muduo TcpConnection 没有提供 close,而只提供 shutdown ,这么做是为了收发数据的完整性。

TCP 是一个全双工协议,同一个文件描述符既可读又可写, shutdownWrite() 关闭了“写”方向的连接,保留了“读”方向,这称为 TCP half-close。如果直接 close(socket_fd),那么 socket_fd 就不能读或写了。

用 shutdown 而不用 close 的效果是,如果对方已经发送了数据,这些数据还“在路上”,那么 muduo 不会漏收这些数据。换句话说,muduo 在 TCP 这一层面解决了“当你打算关闭网络连接的时候,如何得知对方有没有发了一些数据而你还没有收到?”这一问题。当然,这个问题也可以在上面的协议层解决,双方商量好不再互发数据,就可以直接断开连接。

等于说 muduo 把“主动关闭连接”这件事情分成两步来做,如果要主动关闭连接,它会先关本地“写”端,等对方关闭之后,再关本地“读”端。练习:阅读代码,回答“如果被动关闭连接,muduo 的行为如何?” 提示:muduo 在 read() 返回 0 的时候会回调 connection callback,这样客户代码就知道对方断开连接了。

Muduo 这种关闭连接的方式对对方也有要求,那就是对方 read() 到 0 字节之后会主动关闭连接(无论 shutdownWrite() 还是 close()),一般的网络程序都会这样,不是什么问题。当然,这么做有一个潜在的安全漏洞,万一对方故意不不关,那么 muduo 的连接就一直半开着,消耗系统资源。

完整的流程是:我们发完了数据,于是 shutdownWrite,发送 TCP FIN 分节,对方会读到 0 字节,然后对方通常会关闭连接,这样 muduo 会读到 0 字节,然后 muduo 关闭连接。(思考题,在 shutdown() 之后,muduo 回调 connection callback 的时间间隔大约是一个 round-trip time,为什么?)

另外,如果有必要,对方可以在 read() 返回 0 之后继续发送数据,这是直接利用了 half-close TCP 连接。muduo 会收到这些数据,通过 message callback 通知客户代码。

那么 muduo 什么时候真正 close socket 呢?在 TcpConnection 对象析构的时候。TcpConnection 持有一个 Socket 对象,Socket 是一个 RAII handler,它的析构函数会 close(sockfd_)。这样,如果发生 TcpConnection 对象泄漏,那么我们从 /proc/pid/fd/ 就能找到没有关闭的文件描述符,便于查错。

muduo 在 read() 返回 0 的时候会回调 connection callback,然后把 TcpConnection 的引用计数减一,如果 TcpConnection 的引用计数降到零,它就会析构了。

参考:

《TCP/IP 详解》第一卷第 18.5 节,TCP Half-Close。

《UNIX 网络编程》第一卷第三版第 6.6 节, shutdown() 函数。

muduo 的 shutdown() 没有直接关闭 TCP 连接?的更多相关文章

  1. HTTP的RST包与WinHttp延迟关闭TCP连接

    一.RST包也常见于断开TCP连接  几个月前用wireshark抓HTTP包发现有的网络通信在结束的时候没有使用四次握手,而是直接使用RST包.如: 在TCP协议中RST表示复位,用来异常的关闭连接 ...

  2. golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期

    欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...

  3. Linux 内核协议栈之TCP连接关闭

    Close行为: 当应用程序在调用close()函数关闭TCP连接时,Linux内核的默认行为是将套接口发送队列里的原有数据(比如之前残留的数据)以及新加入 的数据(比如函数close()产生的FIN ...

  4. TCP连接的关闭

    原文地址:http://lib.csdn.net/article/computernetworks/17264   TCP连接的关闭有两个方法close和shutdown,这篇文章将尽量精简的说明它们 ...

  5. 我为 Netty 贡献源码 | 且看 Netty 如何应对 TCP 连接的正常关闭,异常关闭,半关闭场景

    欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 写在前面..... 本文是笔者肉眼盯 Bug 系列的第三弹,前 ...

  6. 7.1.1.关闭WebSocket连接

    7.1.定义 7.1.1.关闭WebSocket连接 为_关闭WebSocket连接_,端点需关闭底层TCP连接.端点应该使用一个方法完全地关闭TCP连接,以及TLS会话,如果合适,丢弃任何可能已经接 ...

  7. close_wait状态和time_wait状态(TCP连接)

    1.CLOSE_WAIT的简单解决方案 不久前,我的Socket Client程序遇到了一个非常尴尬的错误.它本来应该在一个socket长连接上持续不断地向服务器发送数据,如果socket连接断开,那 ...

  8. TCP系列07—连接管理—6、TCP连接管理的状态机

            经过前面对TCP连接管理的介绍,我们本小节通过TCP连接管理的状态机来总结一下看看TCP连接的状态变化 一.TCP状态机整体状态转换图(截取自第二版TCPIP详解) 二.TCP连接建立 ...

  9. 简述TCP连接的建立与释放(三次握手、四次挥手)

    在介绍TCP连接的建立与释放之前,先回顾一下相关知识. TCP是面向连接的运输层协议,它提供可靠交付的.全双工的.面向字节流的点对点服务.HTTP协议便是基于TCP协议实现的.(虽然作为应用层协议,H ...

随机推荐

  1. thinkphp5学习总结!

    数据库操作之原生sql操作 <?php namespace app\index\controller; use think\Db; class Index { public function i ...

  2. python3操作数据库 借助pycharm快速连接并操作mysql数据库

    1.https://blog.csdn.net/qiushi_1990/article/details/78041299

  3. keepalived vrrp_script脚本不执行解决办法

    首先打开日志观察: tail -f /var/log/messages 然后新开一个客户端重启keepalived , systemctl restart keepalived.service 看日志 ...

  4. MVC常用特性使用

    简介 在以前的文章中,我和大家讨论如何用SingalR和数据库通知来完成一个消息监控应用. 在上一篇文章中,我介绍了如何在MVC中对MongoDB进行CRUD操作. 今天,我将继续介绍一些在开发中非常 ...

  5. Ansible Tower系列 二(安装 Tower)【转】

    文档:http://docs.ansible.com/ansible-tower/ 安装前检查 python版本为2.6 保持网络畅通 内存预留充足 安装用户为root 软件下载 下载地址:http: ...

  6. (转载)mysql:设置mysql的远程访问

    1.登陆Mysqlmysql -u root -p2.允许任何IP访问,其中密码为admingrant all privileges on *.* to root@"%" iden ...

  7. spring-dao.xml 模板

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  8. JQ实现弹幕效果

    JQ实现弹幕效果,快来吐糟你的想法吧 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta charse ...

  9. Ubuntu18.04安装和配置 Java JDK 和 JRE,并卸载自带OpenJDK

    https://blog.csdn.net/freeking101/article/details/80522586

  10. T-SQL语句2

    一.修改表 1.alter table 语句 alter table database_name,table_name,column_name,type_name//database_name指数据库 ...