(原创)如何使用boost.asio写一个简单的通信程序(二)
先说下上一篇文章中提到的保持io_service::run不退出的简单办法。因为只要异步事件队列中有事件,io_service::run就会一直阻塞不退出,所以只要保证异步事件队列中一直有事件就行了,如何让异步事件队列中一直有事件呢?一个简单的办法就是循环发起异步读操作,如果对方一直都不发数据过来,则这个异步读事件就会一直在异步事件队列中,这样io_service::run就不会退出了。但是这样有一个缺点就是io_service::run处于阻塞会阻塞当前线程,如果不希望阻塞当前线程,就还是通过work来保持io_service::run不退出。
现在言归正传,看看如何用asio写一个简单的客户端。我希望这个客户端具备读写能力,还能自动重连。我希望用一个连接器类去实现连接以及IO事件的处理,连接器具体的职责有三个:1.连接到服务器;2.重连。3.通过事件处理器实现读写。其中,实现重连可以用一个专门的线程去检测,为了简单,不设置重连次数,保持一直重连。实现读写可以直接用上篇中的RWHandler。看看连接器Connctor是如何写的:
class Connector
{
public: Connector(io_service& ios, const string& strIP, short port) :m_ios(ios), m_socket(ios),
m_serverAddr(tcp::endpoint(address::from_string(strIP), port)), m_isConnected(false), m_chkThread(nullptr)
{
CreateEventHandler(ios);
} ~Connector()
{
} bool Start()
{
m_eventHandler->GetSocket().async_connect(m_serverAddr, [this](const boost::system::error_code& error)
{
if (error)
{
HandleConnectError(error);
return;
}
cout << "connect ok" << endl;
m_isConnected = true;
m_eventHandler->HandleRead(); //连接成功后发起一个异步读的操作
}); boost::this_thread::sleep(boost::posix_time::seconds());
return m_isConnected;
} bool IsConnected() const
{
return m_isConnected;
} void Send(char* data, int len)
{
if (!m_isConnected)
return; m_eventHandler->HandleWrite(data, len);
} void AsyncSend(char* data, int len)
{
if (!m_isConnected)
return; m_eventHandler->HandleAsyncWrite(data, len);
} private:
void CreateEventHandler(io_service& ios)
{
m_eventHandler = std::make_shared<RWHandler>(ios);
m_eventHandler->SetCallBackError([this](int connid){HandleRWError(connid); });
} void CheckConnect()
{
if (m_chkThread != nullptr)
return; m_chkThread = std::make_shared<std::thread>([this]
{
while (true)
{
if (!IsConnected())
Start(); boost::this_thread::sleep(boost::posix_time::seconds());
}
});
} void HandleConnectError(const boost::system::error_code& error)
{
m_isConnected = false;
cout << error.message() << endl;
m_eventHandler->CloseSocket();
CheckConnect();
} void HandleRWError(int connid)
{
m_isConnected = false;
CheckConnect();
} private:
io_service& m_ios;
tcp::socket m_socket; tcp::endpoint m_serverAddr; //服务器地址 std::shared_ptr<RWHandler> m_eventHandler;
bool m_isConnected;
std::shared_ptr<std::thread> m_chkThread; //专门检测重连的线程
};
注意看连接成功之后,我发起了一个异步读操作,它的作用除了接收数据之外,还可以用来判断连接是否断开,因为当连接断开时,异步接收事件会触发,据此可以做重连操作。可以看到,在连接失败后,或者读写发生错误之后我会关闭连接然后开始自动重连。
再看看测试代码:
int main()
{
io_service ios;
boost::asio::io_service::work work(ios);
boost::thread thd([&ios]{ios.run(); }); Connector conn(ios, "127.0.0.1", );
conn.Start(); if (!conn.IsConnected())
{
Pause();
return -;
} const int len = ;
char buf[len] = ""; while (std::cin.getline(line, sizeof(line)))
{
conn.Send(line, sizeof(line));
} return ;
}
注意看我是通过work和一个专门的线程的线程去run保持io_service不退出的。 至此,一个简单的客户端完成了。 不过,我并没有提到如何异步发送,异步发送稍微麻烦一点,它涉及发送队列以及如何异步循环发送的问题,为了简单起见就没有专门去讲它,也许后面会用专门的篇幅去讲异步发送。一般情况下同步发送足够了,如果希望更高的发送效率,可以考虑半同步半异步的线程池去发送,以提高效率。
如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。
c++11 boost技术交流群:296561497,欢迎大家来交流技术。
(原创)如何使用boost.asio写一个简单的通信程序(二)的更多相关文章
- (原创)如何使用boost.asio写一个简单的通信程序(一)
boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...
- Python3的tkinter写一个简单的小程序
一.这个学期开始学习python,但是看了python2和python3,最后还是选择了python3 本着熟悉python的原因,并且也想做一些小程序来增加自己对python的熟练度.所以写了一个简 ...
- [pixhawk笔记]4-如何写一个简单的应用程序
本文主要内容来自于:https://dev.px4.io/en/tutorials/tutorial_hello_sky.html,并对文档中的部分问题进行更正. 本文假设已经建立好开发环境并能正确编 ...
- 用c++写一个简单的计算器程序
// 050305.cpp : 定义控制台应用程序的入口点.// // 050304.cpp : 定义控制台应用程序的入口点.////四则运算#include "stdafx.h" ...
- 一步一步写一个简单通用的makefile(二)
这一篇源代码沿用上一篇的源代码hellomake.c hellofunc.c hellofunc.h makefile 但是代码内容和结构有变化,如下: . ├── include │ └── h ...
- python3 写一个简单的websocket程序(转)
原贴:https://segmentfault.com/q/1010000009284816?_ea=1883181 也是找了好久 #! /usr/bin/env python # -*- codin ...
- 一步一步写一个简单通用的makefile(三)
上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...
- 如何用 Python 写一个简易的抽奖程序
不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...
- linux设备驱动第三篇:如何写一个简单的字符设备驱动?
在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存 ...
随机推荐
- 基于JavaWeb实现的研究室综合系统
代码地址如下:http://www.demodashi.com/demo/14641.html 概述 基于JavaWeb实现的研究室综合系统,功能包括研究室成员注册.登陆,后台管理,相册功能,新闻模块 ...
- iOS中判断网络是否联网
#import "AppDelegate.h" #import "ViewController.h" #import "Reachability.h& ...
- iOS应用间相互跳转
使用第三方用户登录,跳转到需授权的App.如QQ登录,微信登录等. 需要用户授权,还需要"返回到调用的程序,同时返回授权的用户名.密码". 应用程序推广,跳转到另一个应用程序(本机 ...
- Linux运维工程师面试-部分题库
一.Linux操作系统知识 1.常见的Linux发行版本都有什么?你最擅长哪一个?它的官网网站是什么?说明你擅长哪一块? 2.Linux开机启动流程详细步骤是什么?系统安装完,忘记密码如何破解? ...
- 【JQuery】jquery对象和javascript对象即DOM对象相互转换
jQuery 对象是通过 jQuery 包装DOM 对象后产生的对象.jQuery 对象是 jQuery 独有的,其可以使用 jQuery 里的方法,但是不能使用 DOM 的方法:例如: $(&quo ...
- tomcat默认密码,admin,manager密码需要自己设置,tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="tomc ...
- [Warning] TIMESTAMP with implicit DEFAULT value is deprecated
启动mysql时,报如下警告信息: [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explic ...
- 还没被玩坏的robobrowser(3)——简单的spider
背景 做一个简单的spider用来获取python selenium实战教程的一些基本信息.因为python selenium每年滚动开课,所以做这样一个爬虫随时更新最新的开课信息是很有必要的. 预备 ...
- 15. 使用Apache Curator装饰ZooKeeper
Apache ZooKeeper是为了帮助解决复杂问题的软件工具,它可以帮助用户从复杂的实现中解救出来. 然而,ZooKeeper只暴露了原语,这取决于用户如何使用这些原语来解决应用程序中的协调问题. ...
- 大批量导入数据的SqlBulkCopy类
SqlBulkCopy 这个类用于数据库大批量的数据传递,通常用于新旧数据库之间的更新.关键的一点是,即使表结构不同,也可以通过表字段或者字段位置建立映射关系,将所需的数据导入到目标数据库. 下面代 ...