boost asio tcp server 拆分
从官方给出的示例中对于 boost::asio::ip::tcp::acceptor 类的使用,是直接使用构造函数进行构造对象,这一种方法用来学习是一个不错的方式。
但是要用它来做项目却是不能够满足我们的需求的,可它有相应的接口,可以让我们更灵活的使用它来做我们的项目。我们可以把这个accptor 的使用拆分开来,就是分成几个步骤来做。这样我们就可以在我们的项目中,在多个函数里面对它进行一步一步的生成。
简单的用法:
#include <iostream> #include <boost/asio/io_service.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp> 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(boost::shared_ptr<boost::asio::ip::tcp::socket> conn);
void handle_msg(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
boost::shared_array<char> sa_len,
const boost::system::error_code &ec,
std::size_t bytes_transfered); // 这里将这些对象,写为全局的,在实际的代码中,应该是一个类的成员变量或者其他方式存在
boost::asio::io_service io_svc; // io service 实例
boost::asio::ip::address_v4 lis_ip; // 默认监听本机所有IP
boost::asio::ip::tcp::endpoint lis_ep(lis_ip, );
boost::asio::ip::tcp::acceptor acceptor(io_svc, lis_ep); int main(int argc, char *argv[])
{
async_accept(); io_svc.run(); return ;
} void async_accept()
{
boost::shared_ptr<boost::asio::ip::tcp::socket> new_sock
= boost::make_shared<boost::asio::ip::tcp::socket>(boost::ref(io_svc));
acceptor.async_accept(*new_sock,
boost::bind(handle_accept, new_sock, boost::asio::placeholders::error) );
} void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> new_conn,
const boost::system::error_code &ec)
{
if (ec != )
{
//LOG_INFO(get_logger(), "accept failed: " << ec.message());
std::cout << "accept failed: " << ec.message() << std::endl;
return ;
}
//LOG_INFO(get_logger(), "a new client connected." << new_conn->remote_endpoint());
std::cout << "a new client connected." << new_conn->remote_endpoint() << std::endl; async_read(new_conn); // 处理下一个连接,每次处理完了之后,需要再次accept。
// 否则BOOST 将只处理一次,然后结束监听。
// 所以这里可以处理一个情况,就是当你要结束监听的时候,只要在这里return
// 那么io_service 的run() 函数就结束监听。但如果有其他的异步操作时,
// run() 函数还是会继续运行的。
async_accept();
} void async_read(boost::shared_ptr<boost::asio::ip::tcp::socket> conn)
{
static const int PACKAGE_LENGTH = ;
// 数据报文长度为 6个字节
boost::shared_array<char> sa_len(new char[PACKAGE_LENGTH]); // 回调函数
boost::function<void (const boost::system::error_code &, std::size_t)> cb_msg_len;
cb_msg_len = boost::bind(handle_msg, conn, sa_len, _1, _2); // 异步读,读一个报文的长度,boost::asio::async_read() 函数有个特点,
// 它会将这里指定的buffer 缓冲区读满了才会去回调handle_msg 函数,
boost::asio::async_read(*conn,
boost::asio::buffer(sa_len.get(), PACKAGE_LENGTH), cb_msg_len); } void handle_msg(
boost::shared_ptr<boost::asio::ip::tcp::socket> conn,
boost::shared_array<char> sa_len,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
if (!conn->is_open())
{
//LOG_INFO(g_logger, "socket was not opened.");
std::cout << "socket was not opened." << std::endl;
//handle_dis_connect(conn);
return ;
} if (ec != )
{
if (ec == boost::asio::error::eof)
std::cout << "Disconnect from " << conn->remote_endpoint() << std::endl;
else
std::cout << "Error on receive: " << ec.message() << std::endl; //handle_dis_connect(the_conn);
return ;
} // 这里对接收到的数据做处理
// ... // 处理完了之后,类似accept 的异常调用一样,需要继续调用异步的读数据
// 同样的,如果要结束一个连接,正常的结束应该在这里return 调用。
// 当然了,使用socket 的close() shut_down() 函数也可以关闭这个连接。
async_read(conn);
}
发现个严重的问题,asio_server 类是个单独的类,而在这个类的成员函数中对this 指针做了操作,而且是将该指针以参数的形式传递给了一个函数指针。这样做是非常危险的,如果在main() 函数中实例化了一个asio_server 对象然后传入到io_service 中,然后asio_server 的实例生命周期到了,那么它的this 指针 则是一个野 指针,这样在asio_serivce 中却有可能 还在使用它,那我们就知道会发生什么危险的事情了。所以下面的代码不可取,我们可以将asio_server 派生自boost::enable_shared_from_this<asio_server> 如果需要还可以派生自boost::noncopyable,然后在用到this 的地方使用成boost::enable_shared_from_this 的一个成员函数 shared_from_this() 来获取到该对象的一个shred_ptr 对象,当然了对于asio_server 也需要用boost::shared_ptr 来构造。
灵活的用法:
// main.cpp #include <iostream> #include <boost/asio/io_service.hpp> #include "asio_server.h" #include <middle/base/log.h> log4cplus::Logger g_logger; int main(int argc, char *argv[])
{
if (argc < )
{
std::cout << "Usage: " << argv[] << " <config>." << std::endl;
return -;
} const char *str_log_cfg = argv[];
const std::string APPENDER_NAME = "pack_back_svr";
log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT(str_log_cfg));
g_logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT(APPENDER_NAME)); boost::asio::io_service io_svc; // io service 实例 asio_server server_01(io_svc);
server_01.listen("", ""); io_svc.run(); return ;
}
// asio_server.h
#ifndef ASIO_SERVER_H
#define ASIO_SERVER_H #include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/shared_array.hpp> class asio_server
{
public:
asio_server(boost::asio::io_service &io_svc);
~asio_server(); bool listen(const char *lis_ip, const char *lis_port);
bool listen(const char *lis_ip, unsigned short lis_port);
bool listen(const char *lis_port);
bool listen(unsigned short lis_port); private:
void async_accept();
void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock,
const boost::system::error_code &ec); void handle_new_connect(boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock);
void start_read(boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock); void handle_msg(
boost::shared_ptr<boost::asio::ip::tcp::socket> the_conn,
boost::shared_array<char> sa_len,
const boost::system::error_code &ec,
std::size_t bytes_transfered); private:
boost::asio::io_service &m_io_svc;
boost::asio::ip::tcp::acceptor m_acceptor;
}; #endif
// asio_server.cpp
#include "asio_server.h" #include <stdio.h>
#include <stdlib.h>
#include <iostream> #ifdef WIN32 # include <windows.h> // windows 下没有snprintf 使用_snprintf 替换
# ifndef snprintf
# define snprintf _snprintf
# endif #endif #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp> #include <middle/base/log.h> extern log4cplus::Logger g_logger; asio_server::asio_server(boost::asio::io_service &io_svc)
: m_io_svc(io_svc)
, m_acceptor(m_io_svc)
{ } asio_server::~asio_server()
{ } bool asio_server::listen(const char *lis_ip, const char *lis_port)
{
if (lis_port == NULL || lis_port[] == )
{
LOG_ERROR(g_logger, "listen port is NULL.");
return false;
} unsigned short us_port = ;
if (sscanf(lis_port, "%hu", &us_port) != )
{
// printf("Error: listen port <==> \"%s\"", lis_port);
LOG_ERROR(g_logger, "listen port: " << lis_port);
return false;
} return listen(lis_ip, us_port);
}
bool asio_server::listen(const char *lis_ip, unsigned short lis_port)
{
boost::asio::ip::address_v4 lis_addr;
if (lis_ip != NULL && lis_ip[] != )
lis_addr = boost::asio::ip::address_v4::from_string(lis_ip); boost::asio::ip::tcp::endpoint lis_ep;
lis_ep.address(lis_addr);
lis_ep.port(lis_port); boost::system::error_code ec_temp;
m_acceptor.open(boost::asio::ip::tcp::v4());
m_acceptor.bind(lis_ep, ec_temp);
if (ec_temp != )
{
LOG_ERROR(g_logger, "bind failed: " << ec_temp.message());
return false;
}
m_acceptor.listen(); LOG_INFO(g_logger, "listen ==> " << m_acceptor.local_endpoint()); async_accept(); return true;
}
bool asio_server::listen(const char *lis_port)
{
unsigned short us_port = ;
sscanf(lis_port, "%hu", &us_port); return listen("", us_port);
}
bool asio_server::listen(unsigned short lis_port)
{
return listen("", lis_port);
} void asio_server::async_accept()
{
try
{
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& error)> cb_accept;
cb_accept = boost::bind(&asio_server::handle_accept, this,
new_sock, boost::asio::placeholders::error); m_acceptor.async_accept(*new_sock, cb_accept);
}
catch (boost::system::system_error& e)
{
LOG_ERROR(g_logger, "Exception system_error: " << e.what());
}
catch (std::exception& e)
{
LOG_ERROR(g_logger, "Exception std: " << e.what());
}
catch (...)
{
LOG_ERROR(g_logger, "Unknown exception.");
}
} void asio_server::handle_accept(
boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock,
const boost::system::error_code &ec)
{
if (ec != )
{
LOG_INFO(g_logger, "accept failed: " << ec.message());
return ;
}
LOG_INFO(g_logger, "a new client connected." << sp_new_sock->remote_endpoint()); handle_new_connect(sp_new_sock);
start_read(sp_new_sock); // 处理下一个连接
async_accept();
} void asio_server::handle_new_connect(
boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock)
{
LOG_INFO(g_logger, "handle_new_connect function");
} void asio_server::start_read(
boost::shared_ptr<boost::asio::ip::tcp::socket> sp_new_sock)
{
static const int PACKAGE_LENGTH = ; // 数据报文长度为 6个字节
boost::shared_array<char> sa_len(new char[PACKAGE_LENGTH]); // 回调函数
boost::function<void (const boost::system::error_code &, std::size_t)> cb_msg_len;
cb_msg_len = boost::bind(&asio_server::handle_msg, this,
sp_new_sock, sa_len, _1, _2); // 异步读,读一个报文的长度
boost::asio::async_read(*sp_new_sock,
boost::asio::buffer(sa_len.get(), PACKAGE_LENGTH), cb_msg_len);
} void asio_server::handle_msg(
boost::shared_ptr<boost::asio::ip::tcp::socket> the_conn,
boost::shared_array<char> sa_len,
const boost::system::error_code &ec,
std::size_t bytes_transfered)
{
LOG_INFO(g_logger, "handle message");
}
这里面用到了log4cplus 日志库,主要是用来写日志的,将日志相关的代码用std::cout 替换就可以直接编译运行了。
当然了客户端还需要另外写。
不过你可以在网上找一些TCP 调试工具来测试一下。
boost asio tcp server 拆分的更多相关文章
- boost asio tcp 多线程
common/pools.h // common/pools.h #pragma once #include <string> #include <boost/pool/pool.h ...
- boost asio tcp 多线程异步读写,服务器与客户端。
// server.cpp #if 0 多个线程对同一个io_service 对象处理 用到第三方库:log4cplus, google::protobuf 用到C++11的特性,Windows 需要 ...
- qt+boost::asio+tcp文件传输
客户端: void qt_boost::pbSendFileClicked(){ QString filename = ui.leFileName->text(); QByteArray ba ...
- 编译boost asio http/server 方法
这段时间学习boost 的asio 编程,想编译asio自带的http/server的程序,无奈在网上根本找不到方法,只能自己摸索学习. 登陆boost asio 的example 目录,(我 boo ...
- boost::asio::tcp
同步TCP通信服务端 #include <boost/asio.hpp> #include <iostream> using namespace boost::asio; in ...
- c++ boost asio库初学习
前些日子研究了一个c++的一个socket库,留下范例代码给以后自己参考. 同步server: // asio_server.cpp : コンソール アプリケーションのエントリ ポイントを定義します. ...
- 使用Boost asio实现同步的TCP/IP通信
可以先了解一下Boost asio基本概念,以下是Boost asio实现的同步TCP/IP通信: 服务器程序部分,如果想保留套接字之后继续通信,可以动态申请socket_type,保存指针,因为so ...
- 使用Boost asio实现异步的TCP/IP通信
可以先了解一下Boost asio基本概念,以下是Boost asio实现的异步TCP/IP通信: 服务器: #include "stdafx.h" #include <io ...
- boost asio 异步实现tcp通讯
---恢复内容开始--- asioboost 目录(?)[-] 一前言 二实现思路 通讯包数据结构 连接对象 连接管理器 服务器端的实现 对象串行化 一.前言 boost asio可算是一个简 ...
随机推荐
- [转帖]零投入用panabit享受万元流控设备——搭建篇
原帖地址:http://net.it168.com/a2009/0505/274/000000274918.shtml 你想合理高效的管理内网流量吗?你想针对各个非法网络应用与服务进行合理限制吗?你是 ...
- ajax java base64 图片储存
js代码 //利用formdata上传 var dataUrl = $('#canvas').getDataUrl(); var img = $('<img>').attr('src', ...
- The Non-Inverting Amplifier Output Resistance by Adrian S. Nastase [ Copied ]
Source Address: http://masteringelectronicsdesign.com/the-non-inverting-amplifier-output-resistance/ ...
- 第五章 搭建S3C6410开发板测试环境
开发板是开发和学习嵌入式技术的主要设备.在这章中介绍了S3C6410开发板,它是三星公司推出的一款低功耗.高性价比的RISC处理器.安装串口调试工具:minicom.它的安装步骤:第1步:检测当前系统 ...
- cache manifest 格式
下面说明书写 cache manifest 文件需要遵循的格式.1 首行必须是 CACHE MANIFEST.2 其后,每一行列出一个需要缓存的资源文件名.3 可根据需要列出在线访问的白名单.白名单中 ...
- texturepacker打包图片,场景切换时背景图有黑边
在使用TexturePacker打包图片之后,背景图在场景切换(有切换动画)时,明显能看到有黑边,在百度之后解决了. 知乎上边有网友贴出了两种解决方法,我抄过来如下: 第一种: 修改 ccConfig ...
- Android中使用AlarmManager进程被删除的解决办法
http://blog.csdn.net/zhouzhiwengang/article/details/13022325 在Android中,AlarmManager提供了不受休眠状态的系统定时功能, ...
- 观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 抽象主题(Subject):它把所有观察者对 ...
- 安装第三方Python模块,增加InfoPi的健壮性
这3个第三方Python模块是可选的,不安装的话InfoPi也可以运行. 但是如果安装了,会增加InfoPi的健壮性. 目录 1.cchardet 自动检测文本编码 2.lxml 用于解析 ...
- Asp.net MVC 的八个扩展点
http://www.cnblogs.com/richieyang/p/5180939.html MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供 ...