博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
boost库在工作(30)网络客户端之五
阅读量:4162 次
发布时间:2019-05-26

本文共 4406 字,大约阅读时间需要 14 分钟。

在前面已经学习到客户端同步连接服务器的处理过程,由于同步的关系,前面的代码理解起来是比较简单,也容易接受,但它有一个致命的缺陷,就是在连接过程、在等服务器回应数据时,CPU不能做别的事情,只能在那里等待。这种等待对于有界面的软件来说,是一种不能接受的表现方式。比如当用户点击连接服务器之后,就一直等在那里,什么也不能操作,就算想立即退出程序也不行,必须等服务器回应之后,或者超时连接之后,才可以操作。对于这样的处理方式,没有用户愿意接受,更加没有用户愿意使用这样的软件,因此采用异步来处理网络的方式,就变得很迫切的要求了。对于现代的软件开发人员,还不掌握这种处理的方式,已经很难适应目前客户对软件的要求了。如果要从底层开发一个异步处理的网络库,还是比较费时间的,boost库提供一个比较完美的解决方案。它可以把域名解释、连接服务器、数据发送和接收,都变成一个事件触发的方式来处理。这样就可以当没有事件响应时处理别的事情,当有事件回应时就可以立即处理网络的事情。具体实现的例子如下:
// boost_023.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include 
#include
#include
#include
#include
//封装一个客户端类来处理异常网络处理。class CClient{public: CClient(const std::string& strHost, const std::string& strService, boost::asio::io_service& ioService) :m_resolver(ioService), m_socket(ioService) { //构造HTTP请求发送给服务器. std::ostream requestPacket(&m_request); requestPacket << "GET " << "http://www.boost.org/" << " HTTP/1.0\r\n"; requestPacket << "Host: " << "www.boost.org" << "\r\n"; requestPacket << "Accept: */*\r\n"; requestPacket << "Connection: close\r\n\r\n"; //发送解释域名请求。 boost::asio::ip::tcp::resolver::query query(strHost, strService); m_resolver.async_resolve(query, boost::bind(&CClient::HandleResolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); }private: //域名解释回应。 void HandleResolve(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { if (!err) { //准备连接解释后的IP地址, 以便连接到服务器。 boost::asio::ip::tcp::endpoint endpoint= *endpoint_iterator; m_socket.async_connect(endpoint, boost::bind(&CClient::HandleConnect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } else { std::cout << "Error: " << err.message() << "\n"; } } //连接到服务器成功或者失败。 void HandleConnect(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { if (!err) { //连接到服务器成功,接着发送请求数据给服务器。 boost::asio::async_write(m_socket, m_request, boost::bind(&CClient::HandleWriteRequest, this, boost::asio::placeholders::error)); } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) { //连接服务器失败,继续连接下一个服务器的端点。 m_socket.close(); boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator; m_socket.async_connect(endpoint, boost::bind(&CClient::HandleConnect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } else { std::cout << "Error: " << err.message() << "\n"; } } //当发送请求数据给服务器之后处理。 void HandleWriteRequest(const boost::system::error_code& err) { if (!err) { //发送给服务器成功之后,就可以读取服务器回应的数据。 boost::asio::async_read_until(m_socket, m_response, "\r\n", boost::bind(&CClient::HandleReadStatusLine, this, boost::asio::placeholders::error)); } else { std::cout << "Error: " << err.message() << "\n"; } } //处理服务器回应的数据完整状态行数据。 void HandleReadStatusLine(const boost::system::error_code& err) { if (!err) { //分析回应的数据。 std::istream responsePacket(&m_response); std::string strhttpVersion; responsePacket >> strhttpVersion; unsigned int iStatusCode; responsePacket >> iStatusCode; std::string strStatusMessage; std::getline(responsePacket, strStatusMessage); //输出解释出来的数据。 std::cout << "response: " << strhttpVersion << " " << iStatusCode << " " << strStatusMessage << std::endl; } else { std::cout << "Error: " << err << "\n"; } } private: boost::asio::ip::tcp::resolver m_resolver; //解释域名 boost::asio::ip::tcp::socket m_socket; //收发数据SOCKET。 boost::asio::streambuf m_request; //发送数据缓冲区。 boost::asio::streambuf m_response; //接收数据缓冲区。};//测试网络服务异步处理。void Test(void){ // const std::string strHost("www.boost.org"); const std::string strHttp("http"); //定义IO服务对象。 boost::asio::io_service ioService; CClient client(strHost,strHttp, ioService); ioService.run();}int _tmain(int argc, _TCHAR* argv[]){ Test(); system("pause"); return 0;}
在这个例子里封装一个类CClient来实现客户端与服务器的处理过程。这个类构造时,构造一个域名解释对象query,接着调用域名解释对象的函数async_resolve来发起域名解释异步请求。当域名解释有事件响应时,就会调用函数HandleResolve来处理,在这里解释成功之后,就可以调用SOCKET对象的函数async_connect来进行异步连接服务器。当连接服务器有事件响应时,就会调用函数HandleConnect处理,在这函数里调用async_write函数来对SOCKET进行发送数据给服务器。当服务器有数据回应之后,就会调用函数HandleWriteRequest来处理,然后在这个函数里调用async_read_until函数对SOCKET进行接收数据,当数据接收完成,就调用函数HandleReadStatusLine来处理输出。从这个例子里,可以看到异步处理都是响应式编程,针对事件来处理的,比起同步处理要复杂很多,理解起来要艰难很多。如果要很清楚地理解这种相互的操作,最适合使用UML里的交互图来表达。

转载地址:http://boixi.baihongyu.com/

你可能感兴趣的文章
linux elf tool readelf
查看>>
linux tool objdump
查看>>
linux tool nm
查看>>
字节对齐
查看>>
把类成员函数封装成线程API所需要的函数
查看>>
HTTP Live Streaming直播(iOS直播)技术分析与实现
查看>>
Ribbon界面图标可以直接用PNG做透明图标
查看>>
向其他软件窗口、控件发送消息的方法
查看>>
word或者pdf文件全部保存为图片的方法
查看>>
VS2010下SQLite3生成lib库文件
查看>>
sqlite3的helloworld
查看>>
MFC下支持中文的SQLite3封装类使用
查看>>
简单高效的多线程日志类
查看>>
研华USB4711A采集卡高速中断模式采集总结
查看>>
从零起步CMFCToolBar用法详解
查看>>
CMFCRibbonStatusBar用法
查看>>
CMFCControlRendererInfo类的参数
查看>>
史上最详细MFC调用mapX5.02.26步骤(附地图测试GST文件)
查看>>
CMFCShellListCtrl使用方法
查看>>
mapnik的demo运行
查看>>