先说下上一篇文章中提到的保持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写一个简单的通信程序(二)的更多相关文章

  1. (原创)如何使用boost.asio写一个简单的通信程序(一)

    boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...

  2. Python3的tkinter写一个简单的小程序

    一.这个学期开始学习python,但是看了python2和python3,最后还是选择了python3 本着熟悉python的原因,并且也想做一些小程序来增加自己对python的熟练度.所以写了一个简 ...

  3. [pixhawk笔记]4-如何写一个简单的应用程序

    本文主要内容来自于:https://dev.px4.io/en/tutorials/tutorial_hello_sky.html,并对文档中的部分问题进行更正. 本文假设已经建立好开发环境并能正确编 ...

  4. 用c++写一个简单的计算器程序

    // 050305.cpp : 定义控制台应用程序的入口点.// // 050304.cpp : 定义控制台应用程序的入口点.////四则运算#include "stdafx.h" ...

  5. 一步一步写一个简单通用的makefile(二)

    这一篇源代码沿用上一篇的源代码hellomake.c hellofunc.c hellofunc.h makefile 但是代码内容和结构有变化,如下: . ├── include │   └── h ...

  6. python3 写一个简单的websocket程序(转)

    原贴:https://segmentfault.com/q/1010000009284816?_ea=1883181 也是找了好久 #! /usr/bin/env python # -*- codin ...

  7. 一步一步写一个简单通用的makefile(三)

    上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...

  8. 如何用 Python 写一个简易的抽奖程序

    不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...

  9. linux设备驱动第三篇:如何写一个简单的字符设备驱动?

    在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存 ...

随机推荐

  1. 基于源码编译安装openssh

     最近的,openssl/openssh等相继漏洞的暴露,让暴露在公网的linux.沦陷为肉鸡的正营... 没办法,还是升级版本... 00.openssh简介 OpenSSH 是一组安全远程的连接工 ...

  2. ios中通过过RGB绘制图片

    + (UIImage *) ImageWithColor: (UIColor *) color frame:(CGRect)aFrame { aFrame = CGRectMake(, , aFram ...

  3. 内存问题的排查工具和方法– Clang的AddressSanitizer

    1 概述 Valgrind可以有效地监测处大多数内存问题,你肯定忍不住会想,既然c/c++的内存问题这么常见,为什么不在编译器中加入内存问题检测的功能呢? 很可惜,GCC中还目前还不支持内存检测,可喜 ...

  4. Windows下SVN备份脚本

    本站备份:svn备份与还原_脚本_(dump命令) 以下是转载记录, 转自:https://wuxiaobai.win/archives/111 用法 svnadmin dump REPOS_PATH ...

  5. jsp+easyui+DataGrid 例子

    转自:https://blog.csdn.net/l3922768721/article/details/51597977 导入js和css <%@ page language="ja ...

  6. ajax请求格式

    ajax请求格式........... var rowsData = $('#receiptPrintList').datagrid('getSelections'); $.ajax({ type: ...

  7. Linux init进程学习 转

    http://oss.org.cn/kernel-book/ch13/13.6.1.htm init进程的建立 Linux将要建立的第一个进程是init进程,建立该进程是以调用kernel_threa ...

  8. SpringBoot配置属性转载地址

    SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...

  9. CentOS 7 systemd的坑

    一.概述 在从 CentOS 6 迁移到 CentOS 7 的过程中,可能有一些地方需要调整,最显著的地方莫过于 systemd 带来的改变,不同的管理服务的方式,不同的日志方式,设置时区,时间等等. ...

  10. 【HTML】网页中如何让DIV在网页滚动到特定位置时出现

    用js或者jquery比较好实现.但你要知道,滚动到哪个特定位置,例如滚动到一个标题h3那显示这个div,那么可以用jquery算这个h3距离网页顶部的距离:$("h3").off ...