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

当客户端连接到服务器之后,想要做什么事情呢?其实就跟一个人去看医生一样,先去挂一个号,然后再根据排队的号去看医生,然后再根据医生的处方进行治疗。因此,在客户端和服务器设计上,一般有一条重要的原则,就是作为客户端要主动发起数据给服务器,让服务器知道客户端是来做什么事情的。比如同一个服务器的端口上,可以提供很多种客户端连接,像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);
 
//测试网络服务查询,连接。

void Test(void)
{
//定认一个查询端点对象。
boost::asio::ip::tcp::resolver::query query("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::resolver resolver(ioService);
//进行域名或者服务解释,以便生成SOCKET内部使用的数据格式。
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::resolver::iterator itEnd;
if (iterator == itEnd)
{
     return;
}
 
//解释成功之后, 显示解释后的IP地址和端口。
boost::asio::ip::tcp::endpoint endpoint = iterator->endpoint();
std:: cout << "host_ip:" << endpoint.address() << " port: " <<endpoint.port() << std::endl;
 
//尝试连接服务器。
boost::asio::ip::tcp::socket socket(ioService);
boost::system::error_code errorCode = 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;
}
 
}
 
//与服务器进发送和接收数据。

bool SendRecvData(boost::asio::ip::tcp::socket& socket) 
{
//发送数据给服务器。
//构造HTTP请求。
boost::asio::streambuf request;
    std::ostream requestPacket(&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";
	
	std::cout<<&request<<std::endl;
 
    //通过SOCKET发送数据。
    boost::asio::write(socket,request);
 
//接收服务器回应数据。
boost::asio::streambuf response;
boost::asio::read_until(socket,response, "\r\n");
 
//分析回应的数据。
std::istream responsePacket(&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减少到最低程度,大大地提高代码质量,提高软件开发效率。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值