爱上开源之网络通信库boot4go-fastnet,简单而不乏高能
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爱上开源之网络通信库boot4go-fastnet,简单而不乏高能相关的知识,希望对你有一定的参考价值。
参考技术A 准备在物联网中间件这块做一些创新的产品, 故先提前准备了剥离出以后自己御用的底层tcp通讯的网络库boot4go-fastnet。boot4go-fastnet项目简单,主要代码大小不足20K,但是性能不输其他的网络库。
boot4go-fastnet对网络通讯的优化思想的灵感主要是来自于另一个高性能的http服务fasthttp。 只是fasthttp仅仅只是提供了http的通信实现,并没有在tcp层次上进行实现,在做中间件的过程中,很多的服务都是通过tcp或者端口通信实现的,所以必须要有一个tcp的通讯底层的网络库,对比了网上相对来说比较有名的epoll,gnet,go-netty等项目,其中epoll,gnet都是类似于redis的多路复用的实现方式,
在网络通信的方式上,采取了nio的方式来实现,在看etcd等代码的时候,都没有看到其使用类似的方式,其实go的协程方式,已经非常好的解决了以前bio的弊端,之所以有nio出现,主要是在以往的bio方式中,都有一个线程对于去处理监听得到的连接,
线程的维护开销较大,在大量的长连接的情况下,会导致系统的开销非常的吃紧,这才有了nio的模型,但是在go里,其中的协程对于大量多并发的情况处理,没有线程这样的重,在看看redis的io模型,redis的之所以性能优秀,多路复用是其我们都知道的,但是要知道首先redis是单线程处理,这样他的多路复用才真正的有意义,另外,redis的快,还有个关键点,就是内存复制这块,零拷贝机制,
这也是一个非常的关键点,最后一点,redis是基于内存的操作,通过RDB和AOF结合方式,尽可能减小磁盘写对性能的影响,综合以上,才有了redis的高性能,所以如果一味的说nio就能有网络高性能,就是一叶障目,目光短浅了。 正是有这样的怀疑,所以还是先压数据测性能先, 自己就写了个简单的网络通信库,按照fasthttp的思想,进行以下的优化点实现
1. 引入协程池,将协程的开销进一步压缩
2. 内存复用, 缓存池,对象均使用对象池的实现,进一步减小内存分配和Gc的开销
3. 零拷贝,这里并不是真正的零拷贝,只是通过bytebuffer仅可能的减少不必要的内存拷贝。
看看fastnet和Epoll的PK结果。
两者都在我的机器上,在并发数2000的时候,数据意义比较大,超过2000的时候,会有一些jmeter的报错,数据失真,数据包使用的是不到1k的小包
直接上结果:
boost:asio网络库初学之echo服务器客户端实现
为什么想起来学网络库呢
前一阵在网上看到这么一段话
select 实在是太慢了.
在这种背景下, IBM 老大哥带领着MS老弟先搞了 IOCP . 然而开源的人有开源的做法, 在 NIH 综合症的影响下, BSD 的人敢为天下所不齿, 发明了 Kqueue. 同样在 NIH 综合症影响下, Linux 的一群 M* 的猴子捣鼓出了 epoll.
分裂, 让人头疼.
于是程序员们急需一个上天入地无所不能的法宝的法宝, 把这3家法宝给统御起来。
实在太符合我的心情了,我就很需要这样一个法宝,让自己舒服一点。因为是macos系统,类Unix,在服务器开发方面,linux有的基本都有,差不多是一致的,但就是没有Epoll!!!,这就有些麻烦了,上一次写网关服务器时候,开发过程是这样的:
用sublime远程连接云服务器,
再用终端ssh运行调试,
就这样循环往复,再加上还没有补全,适应了xcode的舒服,所以痛苦ing。
说重点,为什么选择asio呢
1.asio属于boost的一部分,有可能被加入c++标准库,其代码质量稳定性及可靠性已不言而喻。
2.还是c++的原因,其源码使用了大多c++11特性,想在对其源码的学习过程中,对自己的c++知识进行一次加深和巩固
3.其主要针对于异步Proactor模式,而此模式相比较Reactor模式,学习难度稍高,所以想借着学习库使用的同时,能对其源码进行学习,提高事件驱动编程的能力。
4.当然是跨平台了。
代码
客户端
//
// main.cpp
// AsioClient
//
// Created by shiyi on 2016/12/10.
// Copyright © 2016年 shiyi. All rights reserved.
//
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace boost;
int main(int argc, const char * argv[])
asio::io_service service;//创建调度器
asio::ip::tcp::socket sock(service);//创建socket
asio::ip::tcp::endpoint ep(asio::ip::address::from_string("127.0.0.1"), 6666);//创建目标地址对象
//异步连接
sock.async_connect(ep, [](const boost::system::error_code &error)
if(error)
std::cout << error.message() << std::endl;
return;
std::cout << "connect succeed" << std::endl;
);
//如果不进行run调用的话,程序会直接结束,所以这里会等待async_connect结束,
//因此上面connect同步还是异步其实是一样的
service.run();
char data[512];
boost::system::error_code ec;
size_t len;
while(true)
std::cin >> data;
//发送 如果不传入 ec(error_code)参数,则出错时会抛出异常,此时可以用try-catch进行捕获,如果也没捕获,程序会直接终止
len = sock.write_some(asio::buffer(data), ec);
if(ec)
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
//接收
len = sock.read_some(asio::buffer(data), ec);
if(ec)
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
std::cout << data << std::endl;
return 0;
服务端
//
// main.cpp
// AsioServer
//
// Created by shiyi on 2016/12/10.
// Copyright © 2016年 shiyi. All rights reserved.
//
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
using namespace boost;
using socket_ptr = boost::shared_ptr<asio::ip::tcp::socket>;//包装socket类型的智能指针
void client_session(socket_ptr sock)
auto ep = sock->local_endpoint();
std::cout<<ep.address().to_string()<<"连接"<<std::endl;
char data[512];
boost::system::error_code ec;
size_t len;
while(true)
len = sock->read_some(asio::buffer(data), ec);
if(ec)
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
len = sock->write_some(asio::buffer(data), ec);
if(ec)
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
std::cout<<ep.address().to_string()<<"关闭"<<std::endl;
int main(int argc, const char * argv[])
asio::io_service service;//创建调度器
asio::ip::tcp::endpoint ep(asio::ip::address::from_string("127.0.0.1"), 6666);
asio::ip::tcp::acceptor apt(service, ep);//创建连接器
while(true)
socket_ptr sock(new asio::ip::tcp::socket(service));
apt.accept(*sock);//接收新的连接
boost::thread(boost::bind(client_session, sock));//开辟线程去处理该连接上的事务
运行结果
客户端
服务端
以上是关于爱上开源之网络通信库boot4go-fastnet,简单而不乏高能的主要内容,如果未能解决你的问题,请参考以下文章