boost库在工作(29)网络客户端之四

来源:互联网 发布:mysql 压力测试脚本 编辑:程序博客网 时间:2024/05/21 14:50

当客户端连接到服务器之后,想要做什么事情呢?其实就跟一个人去看医生一样,先去挂一个号,然后再根据排队的号去看医生,然后再根据医生的处方进行治疗。因此,在客户端和服务器设计上,一般有一条重要的原则,就是作为客户端要主动发起数据给服务器,让服务器知道客户端是来做什么事情的。比如同一个服务器的端口上,可以提供很多种客户端连接,像HTTP这样的服务器,也就面临着很多不同浏览器连接上来,而服务器要区分不同的浏览器来做不同的事情,那么就需要知道浏览器来做什么事情的,因而浏览器连接成功之后,首先发送数据给服务器,说明协议的版本,浏览器的名称,能接收什么样的数据等内容。这样服务器,就会根据客户端的情况进行区分,放到不同的任务处理队列里,这样服务器兼容处理不同版本协议的客户端情况,实现向下兼容所有以前的版本,达到平滑向前升级的功能。在网络里按服务器与客户端设计时,服务器往往设计上考虑是升级时间比较长,而客户端是随时可以更换或者升级的。这样就导致服务器要兼容不同的版本,以便适应不同的用户需求。比如目前移动系统更新很快,在移动系统开发的APP往往是不同的OS版本,做出来的功能也有区别,但是用户会分布在不同OS的版本上,导致客户端也有新旧之分了,在android版本1.6是1.0版本的客户端,而在android版本2.0是2.0版本的客户端,在android版本4.2是3.0版本的客户端。在这种情况之下,为了不同版本的用户,还继续使用提供的服务,那么就得在服务器端使用不同兼容策略,才可以维护新旧客户的满意度,才可以让旧的客户继续成为你的客户,因为丢失一个旧客户,要花三倍成本去开发一个新客户。在软件设计上与硬件设计上最大的不同,是在于软件设计上需要兼容旧版本,需要维护和升级,可能这就是软件上不能出现硬件上IC产业的原因。下面来看看发送数据的例子,代码如下:

// boost_022.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <boost/asio/ip/tcp.hpp >#include <boost/asio.hpp>#include <iostream>#include <string> bool SendRecvData(boost::asio::ip::tcp::socket& socket); //测试网络服务查询,连接。//软件开发人员:蔡军生  2013-06-10//QQ: 9073204void Test(void){//定认一个查询端点对象。boost::asio::ip::tcp::resolver::queryquery("www.boost.org", "http");std::cout <<"host_name: " << query.host_name() << "service_name:" << query.service_name()     << std::endl; //定义IO服务对象。boost::asio::io_service ioService; //定义解释对象。boost::asio::ip::tcp::resolverresolver(ioService);//进行域名或者服务解释,以便生成SOCKET内部使用的数据格式。boost::asio::ip::tcp::resolver::iteratoriterator = resolver.resolve(query);boost::asio::ip::tcp::resolver::iteratoritEnd;if (iterator == itEnd){     return;} //解释成功之后, 显示解释后的IP地址和端口。boost::asio::ip::tcp::endpointendpoint = iterator->endpoint();std:: cout << "host_ip:" << endpoint.address() << " port: " <<endpoint.port() << std::endl; //尝试连接服务器。boost::asio::ip::tcp::socketsocket(ioService);boost::system::error_codeerrorCode = boost::asio::error::host_not_found; socket.close();socket.connect(*iterator,errorCode); //创建一个SOCKET同步连接,即阻塞式。if (errorCode){     //连接出错。     return;} std::cout << "ConnectSuccess" <<std::endl; //if (!SendRecvData(socket)){     return;} } //与服务器进发送和接收数据。//软件开发人员:蔡军生  2013-06-11//QQ: 9073204bool SendRecvData(boost::asio::ip::tcp::socket& socket) {//发送数据给服务器。//构造HTTP请求。boost::asio::streambuf request;    std::ostreamrequestPacket(&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";     //通过SOCKET发送数据。    boost::asio::write(socket,request); //接收服务器回应数据。boost::asio::streambuf response;boost::asio::read_until(socket,response, "\r\n"); //分析回应的数据。std::istreamresponsePacket(&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; //return true;}  int _tmain(int argc, _TCHAR* argv[]){Test(); system("pause"); return 0;}


在这个例子里,使用一个boost::asio::streambuf对象来构造发送数据包,然后通过boost::asio::write函数把数据通过网络SOCKET对象发送出去,最后为了接收服务器回应的数据,构造boost::asio::streambuf对象来保存数据,通过boost::asio::read_until函数来等服务器到来,直到条件结束。收到数据之后,就可以通过std::istream对象来解释回应的数据,然后把相应的数据输出到控制端窗口。

虽然这个例子短小,但还是把接收和发送的代码分成一个函数SendRecvData,这样更加容易理解和维护。在软件开发里,每个函数不超过屏幕一屏,就是最理想的函数,否则维护成本增加很多,每当开发人员查看代码,再滚屏时,思想就给滚掉了。并且这样可以把BUG减少到最低程度,大大地提高代码质量,提高软件开发效率。

原创粉丝点击