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. 7G

  2. oracle null+字符串问题

    select 10 + 10 + 10 from dual结果是30,完全没问题. select null + 10 + 10 from dual结果是空串,但期望的结果是20. select nvl ...

  3. 1、eureka注册中心单机

    Spring Cloud 2.x系列之 eureka注册中心单机 一.简介 Spring Cloud Eureka是Spring Cloud Netflix项目下的服务治理模块.而Spring Clo ...

  4. 自定义vant ui steps组件效果实现

    记录个问题,当作笔记吧:因为vue项目的移动端vant ui 的step组件跟ui设计图有差别,研究了半天还是没法使用step组件,只能手动设置一个 先上效果图和代码: (1)HTML部分 <d ...

  5. 实现一个EventEmitter类,这个类包含以下方法: on/ once/fire/off

    实现一个EventEmitter类,这个类包含以下方法: on(监听事件,该事件可以被触发多次)- once(也是监听事件,但只能被触发一次)- fire(触发指定的事件)- off(移除指定事件的某 ...

  6. Docker部署web环境之Lanmt

    2. 案例二 整套项目多容器分离通过docker-compose部署lanmt环境 详细的安装准备环境,省略,配置以及部署参考案例一即可 即可实现批量创建web,也可以实现多web共用一个php或my ...

  7. POJ-1155 TELE 树形背包dp

    dp[u][i]代表以u为根的子树选i个叶子的最大收益 那么dp[u][i]=max(dp[u][i],dp[v][k]+dp[u][i-k]-len) (1=<k<=i) 细节看代码: ...

  8. Eclipse快速生成一个JavaBean类的方法

    原文: https://jingyan.baidu.com/article/948f5924156866d80ff5f921.html Eclipse快速生成一个JavaBean类的方法 听语音 | ...

  9. leetcode-12双周赛-1243-数组变换

    题目描述: 自己的提交: class Solution: def transformArray(self, arr: List[int]) -> List[int]: if len(arr) & ...

  10. linux文件目录颜色及特殊权限对应的颜色

    白色:表示普通文件蓝色:表示目录绿色:表示可执行文件红色:表示压缩文件浅蓝色:链接文件红色闪烁:表示链接的文件有问题黄色:表示设备文件灰色:表示其它文件 各种背景颜色的显示和文件的权限有关红色背景:特 ...