免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 10951 | 回复: 42

[C++] Boost asio 连接池问题 [复制链接]

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-15 11:28 |显示全部楼层
本帖最后由 joepayne 于 2017-11-20 19:20 编辑

想建立一个TCP 连接池,所有的请求全部共享这些TCP连接。很久没有接触网络编程了,对ASIO也是第一次接触,不知道这样做可不可以
场景:
有K级别的并发线程,每个线程需要间断性地发请求(比方说每隔200000ns),需要重复10-50次左右,服务端处理每次请求的时间大概在3-10ms,客户端对socket的读写数据都很小,但都是同步的,要求请求的吞吐量尽可能地大

初步想法:
请求的量比较大,每次请求new 一个tcp连接感觉不大现实,所以想预先建立一个TCP连接池,并保持连接是激活状态,每次发请求里直接从池子里取出一个连接,然后直接写数据,读数据,之后将连接返回池子

大神们给给意见,如果想用asio这种跨平台的上层网络库来写一个这样的连接池应该怎么写,如果有大神写过,不知道能否借鉴学习一下=)

------- update ----------
UC网站的页面还是N年前的样子,唯一没变的是仍然是大神们的常聚地,=)

附加为我的测试代码,好像有问题,大神们给看看,感谢!


------- update ----------
根据业内几个大哥的反馈及提示,已经实现了一个看起来似乎可行的简单的服务端多线程异步/客户端同步的一个网络接口,还没有经过严格的测试验证就先不附代码了。这个帖子也会持续更新,还在跟大哥们学习,补充这方面的东西  



test.zip

3.2 KB, 下载次数: 42

论坛徽章:
3
15-16赛季CBA联赛之佛山
日期:2016-11-04 14:21:2015-16赛季CBA联赛之山西
日期:2017-01-05 21:29:2715-16赛季CBA联赛之佛山
日期:2017-07-28 16:27:15
发表于 2017-11-15 14:13 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
发表于 2017-11-15 14:55 |显示全部楼层
没那么复杂
几千个并发线程,并不需要开几千个连接。在客户端,你把要发送的东西放到一个队列里,开个线程池向外发就是了。
服务器端更简单,linux 下直接epoll,侦听一个线程,accept之后放到队列中。有事件就read,读到的数据也是放到一个队列里,由工作线 程去做。
你这个简单的场景下,如果非要用框架,感觉poco,libevent, libev都不错。epoll熟的话,直接写最好。

论坛徽章:
0
发表于 2017-11-15 17:59 |显示全部楼层
你的需求是同步socket,这个简单啊,如果是异步的需求会复杂很多。
首先你要知道怎么建立连接,发送和接收数据。
Daytime.1 - A synchronous TCP daytime client
Daytime.2 - A synchronous TCP daytime server

然后用一个类来维护这些连接,需要用的时候获取,用完返还到池里,记得加锁,这个类基本所用对外的接口都是需要加锁的。
  1. boost::recursive_mutex::scoped_lock lock(mutex_)
复制代码


当然,你还可以增加动态增加/减少连接数量的机制,自动重连之类的机制。

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-15 19:23 |显示全部楼层
本帖最后由 joepayne 于 2017-11-15 19:55 编辑

回复 3# sxcong

感谢回复!
把要发送的东西放到一个队列里,开个线程池向外发就是了

因为客户端是在线的实时请求,不管是线程内的多个请求还是不同线程之间的请求,发送的内容不是一样的,所以这里我不大明白把要发送的东西放到一个队列里,再开线程发是解决什么问题?

然后,想尽可能地做到跨平台,因为服务可能部署在云上也可能部署在内网,如果只是单纯epoll/select/kqueue那套东西这个事情就简单了,所以想尽量能通用一些。

另外我把写的demo代码帖出来了,UC的格式好像有些凌乱,我放附件了,我的做法大概就是用一个queue来把连接维护起来,需要调request的时候就从queue里面取一个连接,进行阻塞式的写读操作,然后归还连接。多多指点啊-)

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-15 19:38 |显示全部楼层
本帖最后由 joepayne 于 2017-11-15 19:57 编辑

回复 4# Fixend


感谢回复!

扯些闲话,5年前写系统编程的时候,记得当时的开发环境是UNIX,当时用的C++版本还是C0*,用的接口也都是posix接口,当下生产环境需要自己部署自己的服务,对外提供接口,需要跨平台,跨语言(这个需要用第三方序列化工具),对性能有一定要求,如果回头还是用posix那堆接口开发成本太大,而且没法跨平台啊,自身再去仔细撸那些代码有些力不从心了,asio感觉挺上层的,也跨平台,所以想就用它封装一下算了。现在回头看C++生态圈子的东西感觉整个世界都变了,

附件有我的测试代码,代码中服务端开了10个线程,异步模型;客户端开了三个线程,每个线程重复发起了5个请求。最终,出现 "Broken pipe" "Socket is not connected" 等错误,感觉是在复用的时候连接就已经断了,导致的错误。我个人认为需要加持长连接,保持激活状态,只是不知道,客户端跟服务端怎么去配置。



论坛徽章:
0
发表于 2017-11-15 20:35 |显示全部楼层
回复 6# joepayne

跟多年前比区别不大,asio很多年前就有了,再之前还有ACE.这些东西10多年前就很多人用。

你这个断开是你自己关掉的,你服务器写不对,都delete掉socket了。
  1.     void onResponseSent(const boost::system::error_code& ec,
  2.                     std::size_t bytes_transferred) {
  3.           if (ec != 0) {
  4.             std::cout << "Error occured! Error code = "
  5.               << ec.value()
  6.               << ". Message: " << ec.message();
  7.           }
  8.           onFinish();
  9.     }
  10.     // Here we perform the cleanup.
  11.     void onFinish() {
  12.           delete this;
  13.     }
复制代码

论坛徽章:
0
发表于 2017-11-15 20:43 |显示全部楼层
回复 5# joepayne

把要发送的东西放到一个队列里,再开线程发是解决什么问题?  


这个是异步的常规做法,队列相当于发送缓冲。如果你用asio的异步发送接口,肯定要加发送缓冲的,
否则,你多线程同时异步发送,会出问题的,只能在缓冲中排队进行发送。

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-15 20:46 |显示全部楼层
本帖最后由 joepayne 于 2017-11-15 20:52 编辑

回复 7# Fixend

对,系统底层的东西基本没多少变化,只是C++标准换血了,特性也多元化了

这个地方我也想到了,是server-side主动关闭的,但是,这里我只是把service线程的资源给释放掉了,其中的socket只是一个shared_ptr,其连接这里并没有释放掉。
  1. private:
  2.         std::shared_ptr<asio::ip::tcp::socket> m_sock;
  3.         std::string m_response;
  4.         asio::streambuf m_request;
复制代码


socket只是在

  1. void InitAccept() {
  2.      std::shared_ptr<asio::ip::tcp::socket> sock = std::make_shared<asio::ip::tcp::socket>(m_ios);
  3.      m_acceptor.async_accept(*sock.get(),
  4.                                           [this, sock](const boost::system::error_code& error) {
  5.                                                           onAccept(error, sock);
  6.                                                    }
  7.                                         );
  8.         }
复制代码
这个函数执行完才断开的,是吧?那这里我应该再维护一个socket池子?

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-15 20:47 |显示全部楼层
回复 8# Fixend


噢,明白。我这里是同步的应该不用缓冲了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP