common/pools.h

 // common/pools.h

 #pragma once

 #include <string>

 #include <boost/pool/pool.hpp>
#include <boost/pool/singleton_pool.hpp> class head
{
public:
head() = default;
~head() = default; static const int HEAD_LENGTH = ;
void serialize();
void parse(); char* get_data();
void set_len_body(int32_t len_body);
int32_t get_len_body() const; private:
char m_data[HEAD_LENGTH];
int32_t m_len_body { };
}; using pool_head = boost::singleton_pool<struct struHead, sizeof(head)>;
using pool_string = boost::singleton_pool<struct struString, sizeof(std::string)>; std::shared_ptr<head> createSharedHead();
std::shared_ptr<std::string> createSharedString();

common/pools.cpp

 // common/pools.cpp

 #include "pools.h"
#include <boost/asio.hpp> void head::serialize()
{
using namespace boost::asio::detail::socket_ops;
int32_t len_net = host_tp_network_long(m_len_body); memcpy(m_data, &len_net, sizeof(len_net));
} void head::parse()
{
using namespace boost::asio::detail::socket_ops;
int32_t len_net = ; memcpy(&len_net, m_data, sizeof(len_net));
m_len_body = network_to_host_long(len_net);
} char* head::get_data()
{
return m_data;
} void head::set_len_body(int32_t len_body)
{
m_len_body = len_body;
} int32_t head::get_len_body() const
{
return m_len_body;
} std::shared_ptr<head> createSharedHead()
{
std::shared_ptr<head> sp(new (pool_head::malloc()) head,
[](head *h)
{
h->~head();
pool_head::free(h);
}); return sp;
} std::shared_ptr<std::string> createSharedString()
{
std::shared_ptr<std::string> sp(new (pool_string::mallock()) std::string,
[](std::string *s)
{
s->~basic_string();
pool_string::free(s);
}); return sp;
}

server/main.cpp

 // server/main.cpp

 #include <iostream>
#include "asio_server.h" #include <Log.h> log4cplus::logger gLog; int main(int argc, char* argv[])
{
log4cplus::initialize();
log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.properties"));
gLog = log4cplus::Logger::getInstance("server"); LOG4CPLUS_INFO_FMT(gLog, "main begin..."); boost::asio::io_service io_svc;
boost::shared_ptr<asio_server> sp_serv
= boost::make_shared<asio_server>(io_svc, "127.0.0.1", );
sp_serv->listen(); // 捕获信号
boost::asio::signal_set sigs(io_svc);
sigs.add(SIGINT);
sigs.add(SIGTERM);
sigs.async_wait([&io_svc](const boost::system::error_code &ec, int sig)
{
LOG4CPLUS_INFO_FMT(gLog, "signal: %d, message: %s", sig, ec.message().c_str());
}); std::vector<std::thread> vecThread;
for (int i = ; i < ; ++i)
{
vecThread.emplace_back(std::thread([&io_svc]()
{
LOG4CPLUS_INFO_FMT(gLog, "thread start...");
io_svc.run();
LOG4CPLUS_INFO_FMT(gLog, "thread finish.");
}));
} for (int i = ; i < vecThread.size(); ++i)
{
vecThread[i].join();
}
assert(io_svc.stopped()); return ;
}

server/asio_server.h

 // server/asio_server.h

 #pragma once

 #include <vector>
#include <string>
#include <cstdint> #include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp> class head; class asio_server : public boost::enable_shared_from_this<asio_server>,
public boost::noncopyable
{
public:
asio_server(boost::asio::io_service &io_svc, const std::string &lis_ip, uint16_t lis_port);
virtual ~asio_server(); bool listen(int accept_num = ); private:
void async_accept();
void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> new_conn,
const boost::system::error_code &ec);
void async_read_head(boost::shared_ptr<boost::asio::ip::tcp::socket> conn);
void hand_head(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
std::shared_ptr<head> sp_hd,
const boost::system::error_code &ec,
std::size_t bytes_transfered);
void async_read_proto(boost::shared_ptr<boost::asio::ip::tcp::socket> conn, int32_t len);
void handle_proto(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
std::shared_ptr<std::string> sp_body,
const boost::system::error_code &ec,
std::size_t bytes_transfered); private:
boost::asio::io_service& m_io_svc;
std::string m_lis_ip;
uint16_t m_lis_port;
boost::asio::ip::tcp::acceptor m_acceptor;
}

server/asio_server.cpp

 // server/asio_server.cpp

 #include "asio_server.h"

 #include <common/pools.h>
#include <atomic>
#include <Log.h>
#include <common.pb.h> extern log4cplus::Logger gLog; asio_server::asio_server(boost::asio::io_service &io_svc,
const std::string &lis_ip, uint16_t lis_port)
: m_io_svc(io_svc)
, m_lis_ip(lis_ip)
, m_lis_port(lis_port)
, m_acceptor(io_vc)
{
boost::asio::ip::address_v4 lis_addr; if (!m_lis_ip.empty())
{
m_lis_addr = boost::asio::ip::address_v4::from_string(m_lis_ip);
}
boost::asio::ip::tcp::endpoint lis_ep(lis_addr, m_lisport); boost::asio::ip::tcp::acceptor acc(io_svc, lis_ep);
m_acceptor = std::move(acc);
} asio_server::~asio_server()
{
} bool asio_server::listen(int accept_num /*= 1*/)
{
if (accept_num <= )
return false; for (int i = ; i < accept_num; ++i)
async_accept(); return true;
} void asio_server::async_accept()
{
LOG4CPLUS_INFO_FMT(gLog, "async_accept waitting..."); boost::shared_ptr<boost::asio::ip::tcp::socket> new_sock
= boost::make_shared<boost::asio::ip::tcp::socket>(boost::ref(m_io_svc)); boost::function<void(const boost::system::error_code &)> cb_accept;
cb_accept = boost::bind(&asio_server::handle_accept, shared_from_this(), new_sock, _1);
m_acceptor.async_accept(*new_sock, cb_accept);
} void asio_server::handle_accept(
boost::shared_ptr<boost::asio::ip::tcp::socket> new_conn,
const boost::system::error_code &ec)
{
static std::atomic<int32_t> s_num = ; if (ec != )
{
LOG4CPLUS_INFO(gLOg, "accept failed: " << ec.message());
return;
}
LOG4CPLUS_INFO(gLog, "a new client connected." << new_conn->remote_endpoint());
LOG4CPLUS_INFO_FMT(gLog, "current connect number: %d", ++s_num); async_read_head(new_conn); // 处理下一个连接,每次处理完了之后,需要再次accept。
// 否则BOOST 将只处理一次,然后结束监听。
// 所以这里可以处理一个情况,就是当你要结束监听 的时候只要在这里return
// 那io_service 的run() 函数就会stop。但如果还有其他的异步操作时,
// run() 函数还是会继续运行。
async_accept();
} void asio_server::async_read_head(boost::shared_ptr<boost::asio::ip::tcp::socket> conn)
{
std::shared_ptr<head> sp_hd = createSharedHead(); // 回调函数
boost::function<void(const boost::system::error_code &std::size_t)> cb_msg_head; cb_msg_head = boost::bind(&asio_server::handle_head, shared_from_this(), conn, sp_hd, _1, _2); // 异步读,读一个报文的长度,boost::asio::async_read() 函数有个特点,
// 它会将这里指定的buffer 缓冲区读满了才会去回调handle_head 函数。
boost::asio::async_read(
*conn, boost::asio::buffer(sp_hd->get_data(), head::HEAD_LENGTH), cb_msg_head);
} void asio_server::handle_head(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
std::shared_ptr<head> sp_hd,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
if (!conn->is_open())
{
LOG4CPLUS_INFO(gLog, "socket was not opened.");
return;
} if (ec != )
{
if (ec == boost::asio::error_eof)
LOG4CPLUS_INFO(gLog, "Disconnect from " << conn->remote_endpoint());
else
LOG4CPLUS_INFO(gLog, "Error on receive: " << ec.message());
} // 这里对的数据做处理
assert(bytes_transfered == head::HEAD_LENGTH);
sp_hd->parse();
LOG4CPLUS_INFO_FMT(gLog, "nLenLoc: %d", sp_hd->get_len_body()); async_read_proto(conn, sp_hd->get_len_body());
} void asio_server::async_read_proto(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn, int32_t len)
{
// 数据部分
std::shared_ptr<std::string> sp_body = createSharedString();
std::string& str_body = *sp_body;
str_body.resize(len); // 回调函数
boost::function<void(const boost::system::error_code &, std::size_t)> cb_proto;
cb_proto = boost::bind(&asio_server::handle_proto, shared_from_this(), conn, sp_body, _1, _2); boost::asio::async_read(*conn,
boost::asio::buffer(&str_body[], len), cb_proto);
} void asio_server::handle_proto(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
std::shared_ptr<std::string> sp_body,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
if (!conn->is_open())
{
LOG4CPLUS_INFO(gLog, "socket was not opened.");
return;
} if (ec != )
{
if (ec == boost::asio::error::eof)
LOG4CPLUS_INFO(gLog, "Disconnect from " << conn->remote_endpoint());
else
LOG4CPLUS_INFO(gLog, "Error on receive: " << ec.message()); return;
} // 可以将下一个消息的到这里,让处理proto 数据的同时下一个数据。
// async_read_head(conn); LOG4CPLUS_INFO_FMT(gLog, "body len: %ld", bytes_transfered);
// 处理这个proto 数据
// ...
// 这里将这个std::string 转换成一个proto, 然后处理这个proto
MessageHead pro;
if (!pro.ParseFromArray(sp_body->data(), (int32_t)bytes_transfered))
{
LOG4CPLUS_ERROR_FMT(gLog, "ParseFromArray() failed.");
return;
} int port = conn->remote_endpoint().port();
LOG4CPLUS_INFO_FMT(gLog, "port: %d\n%s", port, pro.DebugString().c_str()); async_read_head(conn);
}

client/main.cpp

 // client/main.cpp

 #include <iostream>
#include <thread>
#include <vector> #include "asio_client.h"
#include <Log.h> log4cplus::Logger gLog; int main(int argc, char *argv[])
{
log4cplus::initialize();
log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.properties"));
gLog = log4cplus::Logger::getInstance("client"); LOG4CPLUS_INFO_FMT(gLog, "main begin..."); boost::asio::io_service io_svc; for (int i = ; i < ; ++i)
{
boost::shared_ptr<asio_client> client
= boost::make_shared<asio_client>(io_svc, "127.0.0.1", );
client->async_connect();
} std::vector<std::thread> vecThread;
for (int i = ; i < ; ++i)
{
vecThread.emplace_back(std::thread([&io_svc](){
LOG4CPLUS_INFO_FMT(gLog, "thread start...");
io_svc.run();
LOG4CPLUS_INFO_FMT(gLog, "thread finish.");
}));
} for (int i = ; i < vecThread.size(); ++i)
{
vecThread[i].join();
}
assert(io_svc.stopped()); return ;
}

client/asio_client.h

 // client/asio_client.h

 #pragma once

 #include <string>
#include <cstdint>
#include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp> #include <common/pools.h> class asio_client : public boost::enable_shared_from_this<asio_client>
, public boost::noncopyable
{
public:
asio_client(boost::asio::io_service& io_svc,
const std::string &str_svr_ip, uint16_t svr_port);
~asio_client() = default; void async_connect(); protected:
void handle_connect(const boost::system::error_code &ec); void async_write(); void handle_write_head(
const std::shared_ptr<std::string> sp_data_proto,
const boost::system::error_code &ec,
std::size_t bytes_transfered); // 这里的sp_data_proto 在函数中并不需要使用,用它作参数的唯一作用,就是保留它的生命周期,
// 保证在数据写完之前它不会被析构。
// 因为,如果该对象在async_write 还未写之前就被析构的话,就会造成数据的错乱,最终端的数据是错误的。
void handle_write_proto(
const std::shared_ptr<std::string> sp_data_proto,
const boost::system::error_code &ec,
std::size_t bytes_transfered); private:
boost::asio::io_service& m_io_svc;
boost::asio::ip::tcp::endpoint m_svr_ep;
boost::shared_ptr<boost::asio::ip::tcp::socket> m_conn;
}

client/asio_client.cpp

 // client/asio_client.cpp

 #include "asio_client.h"
#include <Log.h>
#include <common.pb.h> extern log4cplus::Logger gLog; asio_client::asio_client(
boost::asio::io_service& io_svc,
const std::string &str_svr_ip,
uint16_t svr_port)
: m_io_svc(io_svc)
{
if (str_svr_ip.empty())
std::abort(); using namespace boost::asio::ip;
address_v4 addr(address_v4::from_string(str_svr_ip));
m_svr_ep.address(addr);
m_svr_ep.port(svr_port); m_conn = boost::make_shared<boost::asio::ip::tcp::socket>(boost::ref(m_io_svc));
} void asio_client::async_connect()
{
LOG4CPLUS_INFO_FMT(gLog, "async_connect waitting..."); boost::function<void(const boost::system::error_code &)> cb_connect
= boost::bind(&asio_client::handle_connect, shared_from_this(), _1);
new_sock->async_connect(m_svr_ep, cb_connect);
} void asio_client::handle_connect(const boost::system::error_code &ec)
{
if (ec != )
{
LOG4CPLUS_INFO(gLog, "connect failed: " << ec.message());
return ;
}
LOG4CPLUS_INFO(gLog, "connect success, server: " << m_conn->remote_endpoint()); async_write();
} void asio_client::async_write()
{
#if 0
message MessageHead
{
optional uint32 FunCode = ;
optional uint32 RequestID = ;
optional uint32 AccountId = ;
optional uint32 AccountId = ;
optional int64 ClientTime = ;
optional uint32 GoodsId = ;
optional bytes UUID = ;
}
#endif if (!m_conn->is_open())
{
LOG4CPLUS_INFO(gLog, "socket was not opened.");
return ;
} if (ec != )
{
if (ec == boost::asio::error::eof)
LOG4CPLUS_INFO(gLog, "Disconnect from " << m_conn->remote_endpoint());
else
LOG4CPLUS_INFO(GLog, "Error on receive: " << ec.message()); return ;
} MessageHead pro; pro.set_funcode();
pro.set_requestid();
pro.set_accountid();
pro.set_clienttime(time(NULL));
pro.set_uuid(std::string("uuid_500384")); std::shared_ptr<std::string> sp_data = createSharedString();
if (!pro.SeralizeToString(sp_data.get()))
{
LOG4CPLUS_ERROR_FMT(gLog, "SeraializeToString failed.");
return;
} LOG4CPLUS_INFO_FMT(gLog, "data.size() = %lld", sp_data->size());
if (sp_data->size() == )
return; std::shared_ptr<head> sp_head = createSharedHead();
sp_head->set_len_body((int32_t)sp_data->size());
sp_head->serialize(); boost::function<void(const boost::system::error_code &, std::size_t)> cb_write_head
= boost::bind(&asio_client::headle_write_head, shared_from_this(), sp_data, _1, _2);
boost::asio::async_write(
*m_conn, boost::asio::buffer(sp_head->get_data(), head::HEAD_LENGTH), cb_write_head);
} void asio_client::handle_write_head(
const std::shared_ptr<std::string> sp_data_proto,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
if (!m_conn->is_open())
{
LOG4CPLUS_INFO(gLog, "socket was not opended.");
return;
} if (ec != )
{
if (ec == boost::asio::error::eof)
LOG4CPLUS_INFO(gLog, "Disconnect from " << m_conn->remote_endpoint());
else
LOG4CPLUS_INFO(gLog, "Error on receive: " << ec.message()); return;
} boost::function<void(const boost::system::error_code &, std::size_t)> cb_write_proto
= boost::bind(&asio_client::handle_write_proto, shared_from_this(), sp_data_proto, _1, _2);
boost::asio::async_write(*m_conn, boost::asio::buffer(*sp_data_proto), cb_write_proto);
} void asio_client::handle_write_proto(
const std::shared_ptr<std::string> sp_data_proto,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
if (!m_conn->is_open())
{
LOG4CPLUS_INFO(gLog, "socket was not opened.");
return;
} if (ec != )
{
if (ec == boost::asio::error::eof)
LOG4CPLUS_INFO(gLog, "Disconnect from " << m_conn->remote_endpoint());
else
LOG4CPLUS_INFO(gLog, "Error on receive: " << ec.message()); return;
} LOG4CPLUS_INFO(gLog, "write proto finished.");
// 数据写完了之后,可以读对端发送过来的数据。
// 如果 不再读对端的数据,直接该socket 将会被断开。
// async_read_head();
}

boost asio tcp 多线程的更多相关文章

  1. boost asio tcp 多线程异步读写,服务器与客户端。

    // server.cpp #if 0 多个线程对同一个io_service 对象处理 用到第三方库:log4cplus, google::protobuf 用到C++11的特性,Windows 需要 ...

  2. 浅谈 Boost.Asio 的多线程模型

    Boost.Asio 有两种支持多线程的方式,第一种方式比较简单:在多线程的场景下,每个线程都持有一个io_service,并且每个线程都调用各自的io_service的run()方法. 另一种支持多 ...

  3. <转>浅谈 Boost.Asio 的多线程模型

    本文转自:http://senlinzhan.github.io/2017/09/17/boost-asio/ Boost.Asio 有两种支持多线程的方式,第一种方式比较简单:在多线程的场景下,每个 ...

  4. boost asio tcp server 拆分

    从官方给出的示例中对于 boost::asio::ip::tcp::acceptor 类的使用,是直接使用构造函数进行构造对象,这一种方法用来学习是一个不错的方式. 但是要用它来做项目却是不能够满足我 ...

  5. qt+boost::asio+tcp文件传输

    客户端: void qt_boost::pbSendFileClicked(){ QString filename = ui.leFileName->text(); QByteArray ba ...

  6. boost::asio::tcp

    同步TCP通信服务端 #include <boost/asio.hpp> #include <iostream> using namespace boost::asio; in ...

  7. BOOST.Asio——Overview

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  啥说的,鄙视那些无视版权随 ...

  8. 如何在多线程leader-follower模式下正确的使用boost::asio。

    #include <assert.h> #include <signal.h> #include <unistd.h> #include <iostream& ...

  9. boost中asio网络库多线程并发处理实现,以及asio在多线程模型中线程的调度情况和线程安全。

    1.实现多线程方法: 其实就是多个线程同时调用io_service::run for (int i = 0; i != m_nThreads; ++i)        {            boo ...

随机推荐

  1. js异步处理

    一.什么是异步? 我们一般喜欢把异步和同步.并行拿出来比较,我以前的理解总是很模糊,总是生硬地记着“同步就是排队执行,异步就是一起执行”,现在一看,当初简直就是傻,所以我们第一步先把这三个概念搞清楚, ...

  2. js浮点金额计算精度

    在js中进行以元为单位进行浮点数计算时,会产生精度问题,例如: console.log(0.1+0.2) 结果为:0.30000000000000004 大多数编程语言计算采用的是IEEE 754 标 ...

  3. Android ADB被占用 重启 ADB方法

    前言 ADB 是 android sdk里面的一个工具,这个工具可以用于操作管理 Android 模拟器 和 真实Andriod手机设备.列如 : 执行安装 删除 应用的操作 , 执行 模拟点击屏幕 ...

  4. 使用openntpd替换ntpd

    系统自带的ntp服务太难用,systemd启动几次没启动起来,懒得折腾,换了openntpd一次成功.

  5. python wave 库 读取 BytesIO 对象的注意事项

    程序中遇到需要使用临时文件时,常使用内存中的 io.BytesIO() 代替实体二进制文件,以避免磁盘IO,同时免去了考虑文件名的麻烦. file = io.BytesIO() file.write( ...

  6. 使用Maven进行依赖管理和项目构建

    什么是Maven 1 依赖的管理:仅仅通过jar包的几个属性,就能确定唯一的jar包,在指定的文件pom.xml中,只要写入这些依赖属性,就会自动下载并管理jar包. 2 项目的构建:内置很多的插件与 ...

  7. MATLAB中图像处理的函数

    表1 图像显示 函数名 功能说明 函数名 功能说明 colorbar 颜色条显示 montage 按矩形剪辑方式显示多帧图像 getimage 从坐标系中获取图像数据 immovie 从多帧索引图像中 ...

  8. WebService发送 方法

    public String disableSaleOut(JSONObject jsonObject) throws ServiceException, MalformedURLException, ...

  9. Python 项目隔离环境virtualenv--venv

    virtualenv 用来为一个应用创建一套“隔离”的python运行环境. 先安装virtualenv: pip3 install virtualenv 再进入项目目录,或者创建一个项目目录并进入, ...

  10. Eclipse中安装SVN插件的艰难旅程

    我们写Java程序的人都知道Eclipse,也装过一些插件,比如Android开发的使用需要安装ADT等,如果代码提交的话我们可能需要安装git和svn的插件,但是这个插件我以前听过,但是一直没有安装 ...