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

muduo源码分析--连接的断开 在Tcp中断开连接比创建连接更加困难         真正执行断开连接的时候是从在channel中的handleEvent函数,在Channel中并没有handleRead、handleWrite、handleClose函数出里的实现,都是借助注册的回调来进行的。         在某一个channel上有事件到达时,执行相应的操作,更具事件类型执行相应的操作这个步骤是在handleEvent 阅读详情

陈硕 (giantchen_AT_gmail)

Blog.youkuaiyun.com/Solstice

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

 

今天收到一位网友来信:

在 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() 函数。

TCP如何关闭连接(详细版) 函数关闭的孤⼉连接,由于⽆法再发送和接收数据,所以这个状态不可以持续太久,⽽tcp_fin_timeout 控制了这个状态下连接的持续时⻓,默认值是。,⾜以让两个⽅向上的数据包都被丢弃,使得原来连接的数据包在⽹络中都⾃然消失,再出现的数据包⼀定都是新建⽴连接所产⽣的。状态,就表示主动⽅的发送通道已经关闭,接下来将等待对⽅发送FIN 报⽂,关闭对⽅的发送通道。,如果接收缓冲区有已接收的数据,则将会被丢弃,并且后续再收到新的数据,会对数据进⾏ ACK。函数的⼀⽅的连接叫做「孤⼉连接」,如果你⽤。 阅读详情

相关推荐

muduo-master.zip

muduo是个基于现代C++高效的高并发网络库,他依赖boost库,由陈硕大神编写. muduo代码结构比较清晰易懂,各个细节处理的非常完美,是一个非常值得学习的开源库。基于他是个网络库,开篇我剖析他的网络相关部分的结果,各个类的继承,调用关系。 网络服务器要处理的对象无外乎,监听者TcpServer,连接接收者Acceptor,连接者TcpConnection等等主体对象。要处理的事件有监听者可写,连接者读写等主体事件。宏观上面,所有的连接可以看作成一个通道Channel,通道有网络IO事件。

muduo源码剖析-TcpServer连接关闭

Server关闭连接的情况有两种,一种是被动关闭,即对方先关闭连接,本地read(2)返回零,触发关闭逻辑。另一种是主动断开连接,即调用TcpConnection::forceClose()函数。 1 被动关闭 时序图如下 对方关闭时,read(2)会收到0字节,因此触发关闭逻辑。首先loop事件循环中channel触发handleEvent,然后调用readCallback_(),readCallback_在TcpConnection的构造函数中已绑定在TTcpConnection::handleRea

qingchengf的博客 656

Sigrity XtractIM实战:5步搞定IC封装宽带模型提取(附BGA案例)

本文通过一个典型BGA封装案例,详细介绍了使用Cadence Sigrity XtractIM工具进行IC封装宽带模型提取的五步实战流程。内容涵盖从环境准备、参数设置、结果验证到模型导出的完整操作,重点阐述了如何利用XtractIM生成高精度、紧凑的宽带SPICE模型,以解决高速电路设计中因封装模型不准导致的信号与电源完整性问题,助力工程师提升仿真精度与设计效率。

a1b2c的博客 320

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

http://blog.youkuaiyun.com/Solstice/article/details/6208634 今天收到一位网友来信: 在 simple 中的 daytime 示例中,服务端主动关闭时调用的是如下函数序列,这不是只是关闭了连接上的写操作吗,怎么是关闭了整个连接? 1: void DaytimeServer::onConnection(const mu...

diaoqu4574的博客 144

进芯AVP28335烧录避坑全记录:CCS、Uniflash、C2Prog、SDFlash四大工具配置详解

本文详细解析了进芯AVP28335芯片在烧录过程中遇到的常见问题及解决方案,涵盖CCS、Uniflash、C2Prog和SDFlash四大工具的配置要点。针对国产器件AVP28335的特殊需求,提供了从开发环境准备到烧录验证的全流程指南,帮助开发者高效完成程序烧录,避免常见陷阱。

weixin_30836759的博客 590

告别地图偏移!手把手教你用MapOnline V1.2在ArcGIS里加载无偏谷歌影像和历史影像

本文详细介绍了如何使用MapOnline V1.2插件在ArcGIS中加载无偏谷歌影像和历史影像,解决GIS工程师长期面临的地图偏移问题。通过三步安装配置、无偏影像加载和时空分析功能,提升地理信息数据的精确度和工作效率,特别适用于城市规划、环境监测等场景。

weixin_29252171的博客 232

muduo库TcpConnection对send、shutdown、SIGPIPE的处理

muduo库对send的处理: muduo库的send()函数重载了三个: void send(const void* message, int len); void send(const StringPiece& message); //短字符优化子string类 void send(Buffer* message); // this one will swap data 分别

FreeeLinux's blog 2125

遥感生态指数(RSEI)——四个指数的计算

遥感生态指数是在4个生态指数的基础上通过主成分变换得出的一个评价生态环境质量的指标。因此,第二部分就是要分别计算出这4个指数的值。 ①首先,是绿度指数的计算,一般用归一化植被指数(NDVI) NDVI=(NIR-Red)/(NIR+Red) 在Bandmath工具中输入NDVI计算公式 (float(b4-b3))/(b4+b3) 其中,b3、b4分别是红波段和近红外波段 ②其次,是湿度计算。 WET = c1B1 + c2B2 + c3B3...

qq_41978498的博客 9万+

Muduo关闭连接

这张图展示了在 Muduo 网络库中,TCP 连接关闭时的一个序列图。这个过程展示了客户端和服务端在发送完数据后的连接关闭步骤,具体涉及到几个类和方法的调用。

qq_59148616的博客 582

【OpenClaw从入门到精通】第20篇:OpenClaw实战—从零搭建教育自动化助教系统(作业批改+智能答疑+学情分析)【2026实测】

本文基于OpenClaw开源框架,聚焦教育行业“答疑重复、批改耗时、学情模糊”三大核心痛点,提供从环境部署到功能落地的全流程实操方案。通过整合QQ群交互、代码分析、数据可视化等技能,构建“智能答疑+作业批改+学情分析”的自动化助教系统。系统支持7×24小时群聊答疑、多语言作业自动评审、学情数据周报生成,经实测可使助教工作时间减少60%、作业批改效率提升5-10倍、学情问题识别提前5周。文中包含完整配置步骤、可直接运行的代码示例及避坑指南,兼顾新手入门与进阶实操,帮助教育工作者快速落地自动化工具,从重复劳动中

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1450

智能车图像处理3-入门级分析2 ---直道冲刺

PS :入门级文章适合新手,如果已经有基础可以去看进阶篇文章。

taiyuezyh的博客 4316

TCP连接关闭—close和shutdown

原文:http://lib.youkuaiyun.com/article/computernetworks/17264 TCP连接的关闭有两个方法close和shutdown,这篇文章将尽量精简的说明它们分别做了些什么。 为方便阅读,我们可以带着以下5个问题来阅读本文: 1、当socket被多进程或者多线程共享时,关闭连接时有何区别? 2、关连接时,若连接上有来自对端的还未

上善若水 2万+

将指定文件夹下每张用LabelImg标注的图片中标注部分抠出来保存到指定文件夹下。

将指定文件夹下每张用LabelImg标注的图片中标注部分抠出来保存到指定文件夹下。

weixin_44119674的博客 440

优雅/粗暴地关闭TCP连接--close-shutdown的选择

一个 TCP 连接需要经过三次握手进入数据传输阶段,最后来到连接关闭阶段。在最后的连接关闭阶段,我们需要重点关注的是“半连接”状态。 因为 TCP 是双向的,这里说的方向,指的是数据流的写入 - 读出的方向。 比如客户端到服务器端的方向,指的是客户端通过套接字接口,向服务器端发送 TCP 报文;而服务器端到客户端方向则是另一个传输方向。在绝大数情况下,TCP 连接都是先关闭一个方向,此时另外一个方向还是可以正常进行数据传输。 举个例子,客户端主动发起连接的中断,将自己到服务器端的数...

u011721450的博客 7458

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

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

今天收到一位网友来信: 在 simple 中的 daytime 示例中,服务端主动关闭时调用的是如下函数序列,这不是只是关闭了连接上的写操作吗,怎么是关闭了整个连接? void DaytimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn) 2: { 3: if (conn->con

鱼思故渊的专栏 1282

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

TCP 的四次挥手,连接关闭的2种方式(close和shutdown)

客户端主动发起连接的中断,将自己到服务器端的数据流方向关闭,此时,客户端不再往服务器端写入数据,服务器端读完客户端数据后就不会再有新的报文到达。但这并不意味着,TCP 连接已经完全关闭,服务器端可能正在对客户端的最后报文进行处理,比如去访问数据库,存入一些数据;或者是计算出某个客户端需要的值,当完成这些操作之后,服务器端把结果通过套接字写给客户端,我们说这个套接字的状态此时是“半关闭”的。最后,服...

lwj的博客 6087

如何正确关闭TCP连接

如何正确关闭TCP连接 参考自:https://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable 假设我们在两个POSIX兼容操作系统上运行以下两个程序,目的是从程序A发送100万字节来编程B(这里可以在此处找到程序): A: sock = socket(AF_INET, SOCK_STREAM, 0); connect(sock, &remot

专注于C/C++/Linux领域创作 6741
上一篇: 陈硕博客文章合集下载(2013-02-01更新)
下一篇: C++ 工程实践(3):采用有利于版本管理的代码格式
陈硕
博客等级 码龄26年 1万+粉丝 144原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值