陈硕 (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的发布订阅功能、数据库连接池(自制),实现了集群部署聊天服务器 本项目应用了muduo网络库、nginx的TCP负载均衡、中间件reids的发布订阅功能、数据库连接...
基于重写的muduo网络库,并可工作于nginx tcp负载均衡环境的集群聊天服务器,使用数据库连接池访问数据库 基于重写的muduo网络库,并可工作于nginx tcp负载均衡环境的集群聊天服务器,使用数据库连接池访问数据库 ...
基于muduo库实现了工作在nginx tcp负载均衡环境中的集群聊天服务器和客户端,采用redis消息队列进行集群,mysql数据库存储 基于muduo库实现了工作在nginx tcp负载均衡环境中的集群聊天服务器和客户端,采用redis消息...
基于nginx tcp负载均衡 + redis的集群聊天服务器,网络层使用muduo库搭建,数据库使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器,网络层使用muduo库搭建,数据库使用MySQL 基于nginx tcp负载均衡 + ...
3. **事件驱动模型**:基于Reactor模式,Muduo能够处理来自多个连接的事件,并且通过回调函数处理网络事件,如读写、连接建立和关闭等。 4. **时间轮定时器**:Muduo提供了一个精确的时间轮定时器,用于设置超时...
基于muduo网络库的集群聊天服务器和客户端源码,使用nginx tcp负载均衡,mysql 基于muduo网络库的集群聊天服务器和客户端源码,使用nginx tcp负载均衡,mysql数据库,redis发布-订阅数据库,redis发布-订阅 基于...
网络服务器要处理的对象无外乎,监听者TcpServer,连接接收者Acceptor,连接者TcpConnection等等主体对象。要处理的事件有监听者可写,连接者读写等主体事件。宏观上面,所有的连接可以看作成一个通道Channel,通道...
这个名为“muduo-0.9.1-beta.tar.gz”的压缩包是muduo的0.9.1 Beta版本,适用于Ubuntu等Linux发行版,提供了muduo库的安装和学习资源。 一、muduo库介绍 muduo由知名C++开发者陈硕开发,它以事件驱动的方式处理...
muduo 实现了对 TCP 和 UDP 协议的支持,包括连接管理、数据传输和异常处理等。此外,它还提供了基于这些基础协议的高级功能,如连接池、心跳检测和超时管理等。 6. **轻量级设计** 为了保持高性能和低内存占用,...
5. **TCP连接**:muduo支持TCP连接,包括TCPAcceptor(用于接收新的TCP连接)和TCPServer(用于启动服务器并管理多个连接)。TCP连接类管理着一个Socket实例,并处理读写事件。 6. **Buffer**:用于高效地处理网络...
muduo网络库是一款专为C++设计的高性能、线程安全的网络库,尤其适用于开发高性能服务器应用。它由知名C++开发者陈硕(Chen Shuo)创建,旨在提供一种高效、简洁的处理网络I/O的方式。muduo网络库基于事件驱动模型,...
### muduo网络库中核心模块TcpServer的核心知识梳理 #### 一、基础知识梳理 ##### 1. 阻塞、非阻塞、同步、异步 - **阻塞(Blocking)**:指当一个线程执行某操作时,如果该操作未完成,则线程将处于等待状态直到...
muduo是一个开源的C++网络库,专为高性能、高并发的服务器设计。这个库由陈硕在2010年开发,它基于事件驱动模型,支持非阻塞I/O,使得在处理大量并发连接时能够保持高效的性能。在本文中,我们将深入探讨muduo网络库...
- **简单TCP协议**:介绍了如何使用Muduo建立TCP连接、发送接收数据等基本操作。 - **文件传输**:演示了如何通过Muduo进行文件传输。 - **聊天服务器**:使用Muduo构建了一个简单的聊天服务器,展示了客户端与...
“muduo”是一个由中国开发者编写的开源库,专为多线程编程设计。它以其高效、稳定和易于使用的特性,在国内的软件开发领域中逐渐受到广泛关注。在深入理解muduo之前,我们首先要了解多线程编程的基础知识。 多线程...
基于muduo库实现的集群聊天服务器,通过mysql存储数据,通过nginx实现tcp负载均衡,通过redis实现集群内服务器间的消息订阅发布。 基于muduo库实现的集群聊天服务器,通过mysql存储数据,通过nginx实现tcp负载均衡,...
6. **完整的TCP和UDP网络编程接口**:muduo提供了易于使用的接口,包括TCP连接管理、UDP套接字操作等。 在实际学习过程中,你将通过以下步骤逐步掌握muduo的使用: 1. **环境配置**:确保你有一个支持C++11的...
《muduo网络库深度解析》 muduo网络库,作为C++11之前的一个高性能、线程安全的网络库,被广泛应用于服务器端的开发。它以其轻量级、高效能和易于扩展的特点,成为了众多开发者在构建高并发、低延迟网络应用时的...