`
ihuashao
  • 浏览: 4725439 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

为什么 muduo 的 shutdown() 没有直接关闭 TCP 连接?

阅读更多

陈硕 (giantchen_AT_gmail)

Blog.csdn.net/Solstice

Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category/779646.aspx

今天收到一位网友来信:

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

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

陈硕答复如下:

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网络库、nginx的TCP负载均衡、中间件reids的发布订阅功能,实现了集群部署聊天服务器.zip

    本项目应用了muduo网络库、nginx的TCP负载均衡、中间件reids的发布订阅功能、数据库连接池(自制),实现了集群部署聊天服务器 本项目应用了muduo网络库、nginx的TCP负载均衡、中间件reids的发布订阅功能、数据库连接...

    基于重写的muduo网络库,并可工作于nginx tcp负载均衡环境的集群聊天服务器,使用数据库连接池访问数据库.zip

    基于重写的muduo网络库,并可工作于nginx tcp负载均衡环境的集群聊天服务器,使用数据库连接池访问数据库 基于重写的muduo网络库,并可工作于nginx tcp负载均衡环境的集群聊天服务器,使用数据库连接池访问数据库 ...

    基于muduo库实现了工作在nginx tcp负载均衡环境中的集群聊天服务器和客户端.zip

    基于muduo库实现了工作在nginx tcp负载均衡环境中的集群聊天服务器和客户端,采用redis消息队列进行集群,mysql数据库存储 基于muduo库实现了工作在nginx tcp负载均衡环境中的集群聊天服务器和客户端,采用redis消息...

    基于nginx tcp负载均衡 + redis的集群聊天服务器,网络层使用muduo库搭建,数据库使用MySQL.zip

    基于nginx tcp负载均衡 + redis的集群聊天服务器,网络层使用muduo库搭建,数据库使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器,网络层使用muduo库搭建,数据库使用MySQL 基于nginx tcp负载均衡 + ...

    Muduo_网络库使用手册

    3. **事件驱动模型**:基于Reactor模式,Muduo能够处理来自多个连接的事件,并且通过回调函数处理网络事件,如读写、连接建立和关闭等。 4. **时间轮定时器**:Muduo提供了一个精确的时间轮定时器,用于设置超时...

    基于muduo网络库的集群聊天服务器和客户端源码,使用nginx tcp负载均衡,mysql数据库,redis发布-订阅.zip

    基于muduo网络库的集群聊天服务器和客户端源码,使用nginx tcp负载均衡,mysql 基于muduo网络库的集群聊天服务器和客户端源码,使用nginx tcp负载均衡,mysql数据库,redis发布-订阅数据库,redis发布-订阅 基于...

    muduo-master.zip

    网络服务器要处理的对象无外乎,监听者TcpServer,连接接收者Acceptor,连接者TcpConnection等等主体对象。要处理的事件有监听者可写,连接者读写等主体事件。宏观上面,所有的连接可以看作成一个通道Channel,通道...

    muduo-0.9.1-beta.tar.gz

    这个名为“muduo-0.9.1-beta.tar.gz”的压缩包是muduo的0.9.1 Beta版本,适用于Ubuntu等Linux发行版,提供了muduo库的安装和学习资源。 一、muduo库介绍 muduo由知名C++开发者陈硕开发,它以事件驱动的方式处理...

    现代 C++ 网络库 muduo

    muduo 实现了对 TCP 和 UDP 协议的支持,包括连接管理、数据传输和异常处理等。此外,它还提供了基于这些基础协议的高级功能,如连接池、心跳检测和超时管理等。 6. **轻量级设计** 为了保持高性能和低内存占用,...

    muduo C++网络库 源码(linux)

    5. **TCP连接**:muduo支持TCP连接,包括TCPAcceptor(用于接收新的TCP连接)和TCPServer(用于启动服务器并管理多个连接)。TCP连接类管理着一个Socket实例,并处理读写事件。 6. **Buffer**:用于高效地处理网络...

    muduo网络库

    muduo网络库是一款专为C++设计的高性能、线程安全的网络库,尤其适用于开发高性能服务器应用。它由知名C++开发者陈硕(Chen Shuo)创建,旨在提供一种高效、简洁的处理网络I/O的方式。muduo网络库基于事件驱动模型,...

    muduo网络库中核心模块TcpServer的核心知识梳理

    ### muduo网络库中核心模块TcpServer的核心知识梳理 #### 一、基础知识梳理 ##### 1. 阻塞、非阻塞、同步、异步 - **阻塞(Blocking)**:指当一个线程执行某操作时,如果该操作未完成,则线程将处于等待状态直到...

    完整muduo网络库

    muduo是一个开源的C++网络库,专为高性能、高并发的服务器设计。这个库由陈硕在2010年开发,它基于事件驱动模型,支持非阻塞I/O,使得在处理大量并发连接时能够保持高效的性能。在本文中,我们将深入探讨muduo网络库...

    muduo库手册

    - **简单TCP协议**:介绍了如何使用Muduo建立TCP连接、发送接收数据等基本操作。 - **文件传输**:演示了如何通过Muduo进行文件传输。 - **聊天服务器**:使用Muduo构建了一个简单的聊天服务器,展示了客户端与...

    muduo 木铎

    “muduo”是一个由中国开发者编写的开源库,专为多线程编程设计。它以其高效、稳定和易于使用的特性,在国内的软件开发领域中逐渐受到广泛关注。在深入理解muduo之前,我们首先要了解多线程编程的基础知识。 多线程...

    基于muduo库实现的集群聊天服务器,通过mysql存储数据,通过nginx实现tcp负载均衡.zip

    基于muduo库实现的集群聊天服务器,通过mysql存储数据,通过nginx实现tcp负载均衡,通过redis实现集群内服务器间的消息订阅发布。 基于muduo库实现的集群聊天服务器,通过mysql存储数据,通过nginx实现tcp负载均衡,...

    muduo_server_learn.zip

    6. **完整的TCP和UDP网络编程接口**:muduo提供了易于使用的接口,包括TCP连接管理、UDP套接字操作等。 在实际学习过程中,你将通过以下步骤逐步掌握muduo的使用: 1. **环境配置**:确保你有一个支持C++11的...

    muduo网络库/网络库/网络库.rar

    《muduo网络库深度解析》 muduo网络库,作为C++11之前的一个高性能、线程安全的网络库,被广泛应用于服务器端的开发。它以其轻量级、高效能和易于扩展的特点,成为了众多开发者在构建高并发、低延迟网络应用时的...

Global site tag (gtag.js) - Google Analytics