Boost.Asio c++ 网络编程翻译(17)

客户端和服务端

在这一章节,我们会深入学习使用Boost.Asio建立不平凡的客户端和服务端应用。你可以运行和测试它们,当你理解时,你可以用它们做框架来构造你自己的应用。

在接下来的例子中:

  • 客户端使用一个用户名(无密码)登录到服务端
  • 所有的连接由客户端建立,当客户端请求时服务端回应
  • 所有的请求和回复都以换行符结尾(’\n’)
  • 对于5秒钟没有ping操作的客户端,服务端自动断开连接

客户端可以发送如下请求:

  • 获得所有连接客户端的列表
  • 客户端可以ping,当它ping时,服务端返回ping ok或者ping client_list_chaned(在接下来的例子中,客户端重新请连接的客户端列表)

为了更有趣一点,我们增加了一些难度:

  • 每个客户端登录6个用户连接,比如Johon,James,Lucy,Tracy,Frank和Abby
  • 每个客户端连接随机地ping服务端(随机7秒;这样的话,服务端会时不时关闭一个连接)

同步客户端/服务端

首先,我们会实现同步应用。你会发现它的代码很直接而且易读的。然而,网络部分不需要它自己的线程,因为所有的网络调用都是阻塞的。

同步客户端

同步客户端以你所期望的穿行方式运行;连接到服务端,登录服务器,然后执行连接循环,比如休眠一下,发起一个请求,读取服务端返回,然后再休眠一会,然后一直循环下去……

因为我们是同步的,所以我们要保持简单。首先,连接到服务器,然后再循环,如下:

ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 8001);
   void run_client(const std::string & client_name) {
       talk_to_svr client(client_name);
       try {
           client.connect(ep);
           client.loop();
       } catch(boost::system::system_error & err) {
           std::cout << "client terminated " << std::endl;
       }

}

下面的代码片段展示了talk_to_svr类:

struct talk_to_svr {
       talk_to_svr(const std::string & username)
           : sock_(service), started_(true), username_(username) {}
       void connect(ip::tcp::endpoint ep) {
           sock_.connect(ep);
       }
       void loop() {
           write("login " + username_ + "\n");
           read_answer();
           while ( started_) {
               write_request();
               read_answer();
               boost::this_thread::sleep(millisec(rand() % 7000));

} }

       std::string username() const { return username_; }

... private:

       ip::tcp::socket sock_;
       enum { max_msg = 1024 };
       int already_read_;
       char buff_[max_msg];
       bool started_;
       std::string username_;

};

在循环中,我们仅仅填充1个比特,一个ping操作然后睡眠,然后读取服务端的返回。我们随机睡眠(有时候超过5秒),这样服务端就会在某个时间点断开我们的连接:

void write_request() {
       write("ping\n");
   }
   void read_answer() {
       already_read_ = 0;
       read(sock_, buffer(buff_),
               boost::bind(&talk_to_svr::read_complete, this, _1, _2));
       process_msg();
   }
   void process_msg() {
       std::string msg(buff_, already_read_);
       if ( msg.find("login ") == 0) on_login();
       else if ( msg.find("ping") == 0) on_ping(msg);
       else if ( msg.find("clients ") == 0) on_clients(msg);
       else std::cerr << "invalid msg " << msg << std::endl;

}

对于读取结果,我们使用在之前章节就有说到的read_complete,来保证我们能都到换行符(’\n’)。逻辑在process_msg()中,在这里我们读取服务端的返回,然后分发到正确的方法:

void on_login() { do_ask_clients(); }
   void on_ping(const std::string & msg) {
       std::istringstream in(msg);
       std::string answer;
       in >> answer >> answer;
       if ( answer == "client_list_changed")
           do_ask_clients();
   }
   void on_clients(const std::string & msg) {
       std::string clients = msg.substr(8);
       std::cout << username_ << ", new client list:" << clients;
   }
   void do_ask_clients() {
       write("ask_clients\n");
       read_answer();
   }
   void write(const std::string & msg) { sock_.write_some(buffer(msg)); }
   size_t read_complete(const boost::system::error_code & err, size_t
   bytes) {
       // ... 和之前一样
   }

当读取服务端对我们ping操作的返回时,如果我们获得client_list_changed,我们重新请求客户端列表。

时间: 2024-12-19 19:43:23

Boost.Asio c++ 网络编程翻译(17)的相关文章

Boost.Asio c++ 网络编程翻译(1)

第一次翻译,希望大家多多指正 实战出精华 Boost.Asio C++ 网络编程 用具体的C++网络编程例子来提升你的技能 John Torjan 用具体的C++网络编程例子来提升你的技能 Copyright ? 2013 Packt Publishing 版权所有,除了在鉴定文章或者评论中进行简单引用,如果没有经过出版者事先的书面授权,该书的任何部分都不能被转载.存储在检索系统中.或者以任何形式和方式传阅. 在这本书准备发行之前,我们已经尽我们最大的努力去保证书中信息的准确性.但是,这本书中包

Boost.Asio c++ 网络编程翻译(20)

异步服务端 这个图表是相当复杂的:从Boost.Asio出来你可以看到4个箭头指向on_accept,on_read,on_write和on_check_ping.着也就意味着你永远不知道哪个异步调用是下一个完成的调用,但是你可以确定的是它是这4个操作中的一个. 现在,我们是异步的了:我们可以继续保持单线程.接受客户端连接是最简单的部分,如下所示: ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001)

Boost.Asio c++ 网络编程翻译(30)[完结]

PS:至此终于完成了Boost.Asio C++ network programming一书的翻译,这是我人生第一本完整翻译的书,从开始的磕磕绊绊,到最后小有心得,我收获很多.我将把这个系列的博客进行整理和校对,希望有兴趣的人可以帮我一起,来给大家提供更好更专业的阅读体验. 句柄追踪信息到文件 默认情况下,句柄的追踪信息被输出到标准错误流(相当于std::cerr).你想把输出重定向到其他地方的可能性是非常高的.对于控制台应用,输出和错误输出都被默认输出到相同的地方,也就是控制台.但是对于一个w

Boost.Asio c++ 网络编程翻译(14)

保持活动 假如,你需要做下面的操作: io_service service; ip::tcp::socket sock(service); char buff[512]; ... read(sock, buffer(buff)); 在这个例子中,sock和buff的存在时间都必须比read()调用的时间要长.也就是说,在调用read()返回之前,它们都必须有效.这就是你期望的:你传给一个方法的所有参数在参数内部都必须有效.当我们采用异步方式时,事情会变得越复杂. io_service servi

Boost.Asio c++ 网络编程翻译(3)

Boost.Asio入门 什么是Boost.Asio 简单来说,Boost.Asio是一个跨平台的.主要用于网络和其他一些底层输入/输出编程的C++库. 计算机网络的设计方式有很多种,但是Boost.Asio的的方式远远优于它们.它在2005年就被包含进Boost,然后被广大Bosot的用户测试并在很多项目中使用,比如Remobo(http://www.remobo.com),可以让你创建你自己的即时私有网络(IPN),libtorrent(http://www.rasterbar.com/pr

Boost.Asio c++ 网络编程翻译(11)

*_at方法 这些方法在一个流上面做随机存取操作.你来指定read和write操作从什么地方開始(offset): async_read_at(stream, offset, buffer [, completion], handler):这种方法在一个指定的流上从offset处開始运行一个异步的read操作,当操作结束时,他会调用handler. handler的格式为:void handler(const boost::system::error_code&  err, size_t byt

Boost.Asio c++ 网络编程翻译(26)

Boost.Asio-其他特性 这章我们讲了解一些Boost.Asio不那么为人所知的特性.标准的stream和streambuf对象有时候会更难用一些,但正如你所见.它们也有它们的益处.最后,你会看到姗姗来迟的Boost.Asio协程的入口,它能够让你的异步代码变的很易读.这是很惊人的一个特性. 标准stream和标准I/O buffer 读这一章节之前你须要对STL stream和STL streambuf对象有所了解. Boost.Asio在处理I/O操作时支持两种类型的buffer: b

Boost.Asio c++ 网络编程翻译(6)

io_service类 你应该已经发现大部分使用Boost.Asio编写的代码都会使用几个ios_service的实例.ios_service是这个库里面最重要的类:它负责和操作系统打交道,等待所有异步操作的结束,然后为每一个异步操作调用完成处理程序. 如果你选择用同步的方式来创建你的应用,你不需要考虑我将在这一节向你展示的东西. 你可以用几种不同的方式来使用io_service.在下面的例子中,我们有3个异步操作,2个socket连接和一个计时器等待: 有一个io_service和一个处理线程

Boost.Asio c++ 网络编程翻译(7)

Boost.Asio基本原理 这一章涵盖了你使用Boost.Asio时必须知道的一些事情.我们也将深入研究比同步编程更机警.更有乐趣的异步编程. 网络API 这一部分包含了当使用Boost.Asio编写网络应用程序时你必须知道的事情. Boost.Asio命名空间 Boost.Asio的一切都需要包含在boost::asio的命名空间或者其子命名空间内. boost::asio:这是核心类和函数所在的地方.重要的类有io_service和streambuf.类似read, read_at, re