47.muduo学习笔记之example_下载文件例子

说明

  1. 这个例子源码位于作者的源代码文件夹下examples/filetransfer文件下下

  2. 实现一个发送文件的命令行小工具,这个工具的协议很简单,在启动时通过命令行参数指定要发送的文件,然后在 2021 端口侦听,每当有新连接进来,就把文件内容完整地发送给对方。

  3. 可以直接用telnet测试,只是服务器把文件发过去后,直接在控制台输出

  4. 发送完就调用shutdownWrite()关闭了“写”方向的连接,保留了“读”方向,这称为 TCP half-close,用 shutdown 而不用 close 的效果是,如果对方已经发送了数据,这些数据还“在路上”,那么 muduo 不会漏收这些数据。Muduo 这种关闭连接的方式对对方也有要求,那就是对方 read() 到 0 字节之后会主动关闭连接(无论 shutdownWrite() 还是 close()),一般的网络程序都会这样,不是什么问题。当然,这么做有一个潜在的安全漏洞,万一对方故意不不关,那么muduo 的连接就一直半开着,消耗系统资源。

  5. 连接关闭流程图
    在这里插入图片描述

  • 那么 muduo 什么时候真正 close socket 呢?在 TcpConnection 对象析构的时候。TcpConnection 持有一个 Socket 对象,Socket 是一个 RAII handler,它的析构函数会 close(sockfd_)

代码,作者一共写了三个版本

第一版

  1. 主要看onConnection()函数,一次性把文件读入内存,一次性调用 send(const string&) 发送完毕,这个版本满足除了“内存消耗只能并发连接数有关,跟文件大小无关”之外的健壮性要求。

  2. 每次建立连接的时候我们都去重新读一遍文件,这是考虑到文件有可能被其他程序修改,如果文件是 immutable 的,整个程序可以共享同一个 fileContent 对象。

  3. 这个版本有一个明显的缺陷,即内存消耗与 (并发连接数 × 文件大小) 成正比,文件越大内存消耗越多,如果文件大小上 GB,只需要建立少量并发连接就能把服务器内存耗尽

第二版

  1. 一块一块地发送文件,减少内存使用,用到了 WriteCompleteCallback,这个版本满足了上述全部健壮性要求。

  2. 为了解决版本一占用内存过多的问题,我们采用流水线的思路,当新建连接时,先发送文件的前 64k 数据,等这块数据发送完毕时再继续发送下 64k 数据,如此往复直到文件内容全部发送完毕。代码中使用了 TcpConnection::setContext() 和getContext() 来保存 TcpConnection 的用户上下文(这里是 FILE*),因此不必使用额外的 std::map<TcpConnectionPtr, FILE*> 来记住每个连接的当前文件位置。

  3. onWriteComplete()会在每次写完发送后再次调用,直到把数据读完

第三版

  1. 和第二版基本完全一样,但是采用 shared_ptr 来管理 FILE*,避免手动调用::fclose(3)。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值