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. mongodb导入json文件

    mongoimport --db test  --collection item --jsonArray  item.json

  2. Centos6.5下rsync+inotify的配置详解

    Centos 6.5配置rsync+inotify实现文件实时同步 1.安装rsync(两台机器执行相同的步骤) yum install gcc yum install rsyncd xinetd - ...

  3. centos6 安装EPEL

    一.安装 32位系统: rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm rpm --i ...

  4. 使用eclipse构建Maven项目及发布一个Maven项目

    开发环境: Eclipse Jee Mars(截止2015年12月1日目前的最新版eclipse4.5),下载地址:http://www.eclipse.org/downloads/ 因为此版本已经集 ...

  5. react-native 报错

    报错信息: java.lang.RuntimeException: Unable to load script from assets 'index.android.bundle'. Make sur ...

  6. Android 7.0 行为变更

    Android 7.0 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更.本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更. 如果您之前发布过 Android 应用,请注意 ...

  7. leetcode 题集

    775. Global and Local Inversions 统计相邻元素组成的逆序对(local inversion)和全局逆序对的数量(global inversion) 思路:local i ...

  8. Java登陆拦截器

    package com.beidou.warehouseerp.interceptor; import com.alibaba.fastjson.JSON; import com.beidou.war ...

  9. ElastAlert告警

    ElastAlert告警 https://blog.csdn.net/qq_38369069/article/details/80842432

  10. shell中信号处理

    参考: Shell 脚本中信号处理实践 Linux Shell 的信号 trap 功能你必须知道的细节   在 unix 里,可能发生的每一种类型的事件都是由一个独立的信号来描述,每一个信号都是一个小 ...