boost asio tcp 多线程
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 多线程的更多相关文章
- boost asio tcp 多线程异步读写,服务器与客户端。
// server.cpp #if 0 多个线程对同一个io_service 对象处理 用到第三方库:log4cplus, google::protobuf 用到C++11的特性,Windows 需要 ...
- 浅谈 Boost.Asio 的多线程模型
Boost.Asio 有两种支持多线程的方式,第一种方式比较简单:在多线程的场景下,每个线程都持有一个io_service,并且每个线程都调用各自的io_service的run()方法. 另一种支持多 ...
- <转>浅谈 Boost.Asio 的多线程模型
本文转自:http://senlinzhan.github.io/2017/09/17/boost-asio/ Boost.Asio 有两种支持多线程的方式,第一种方式比较简单:在多线程的场景下,每个 ...
- boost asio tcp server 拆分
从官方给出的示例中对于 boost::asio::ip::tcp::acceptor 类的使用,是直接使用构造函数进行构造对象,这一种方法用来学习是一个不错的方式. 但是要用它来做项目却是不能够满足我 ...
- qt+boost::asio+tcp文件传输
客户端: void qt_boost::pbSendFileClicked(){ QString filename = ui.leFileName->text(); QByteArray ba ...
- boost::asio::tcp
同步TCP通信服务端 #include <boost/asio.hpp> #include <iostream> using namespace boost::asio; in ...
- BOOST.Asio——Overview
=================================版权声明================================= 版权声明:原创文章 谢绝转载 啥说的,鄙视那些无视版权随 ...
- 如何在多线程leader-follower模式下正确的使用boost::asio。
#include <assert.h> #include <signal.h> #include <unistd.h> #include <iostream& ...
- boost中asio网络库多线程并发处理实现,以及asio在多线程模型中线程的调度情况和线程安全。
1.实现多线程方法: 其实就是多个线程同时调用io_service::run for (int i = 0; i != m_nThreads; ++i) { boo ...
随机推荐
- Java中HashMap与ConcurrentHashMap的区别
从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心. 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从 ...
- 关于JDK,tomcat,eclipse的配置
1.下载安装JDK 在自定义安装路径时,jdk和之后的jre文件夹是属于平行结构,我的安装路径为:D:\jdk\jdk1.6.0_43和D:\jdk\jre6 然后是对环境变量的配置, 计算机→属性→ ...
- HTML + CSS (上)
HTML 概念: 超文本标记语言. 核心: 语义. 主体结构: <!doctype html> //告诉浏览器这是什么语言 html //主体 head //头文件 body //页面主体 ...
- Android ADB被占用 重启 ADB方法
前言 ADB 是 android sdk里面的一个工具,这个工具可以用于操作管理 Android 模拟器 和 真实Andriod手机设备.列如 : 执行安装 删除 应用的操作 , 执行 模拟点击屏幕 ...
- RLO文件名欺骗
windows下面,支持一种特殊的unicode字符RLO,一个字符串中如果有这个字符的话,那么在windows下显示时,就会把RLO右侧的字符串逆序显示出来,原始字符串:abcd[RLO]efgh, ...
- svn - Subversion 命令行客户端工具
SYNOPSIS 总览 svn command [options] [args] OVERVIEW 概述 Subversion 是一个版本控制系统,允许保存旧版本的文件和目录 (通常是源代码),保存一 ...
- push declined due to email privacy restrictions
使用git push到Github网站的时候提示: push declined due to email privacy restrictions 原因 在Github设置里有一个隐私选项 Block ...
- Java中的LinkedHashSet
- php上传文件(简易版)
1.前台form表单处添加 enctype="multipart/form-data" 2. //上传文件保存到目录 header("content-type:text/ ...
- 【操作】Linux快捷键