开发者社区> 技术mix呢> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

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

简介:
+关注继续查看
异步服务端
这个图表是相当复杂的;从Boost.Asio出来你能够看到4个箭头指向on_accept。on_read,on_write和on_check_ping。

着也就意味着你永远不知道哪个异步调用是下一个完毕的调用。可是你能够确定的是它是这4个操作中的一个。

如今。我们是异步的了;我们能够继续保持单线程。接受client连接是最简单的部分。例如以下所看到的:
ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(),
   8001));
   void handle_accept(talk_to_client::ptr client, const error_code & err)
   {
       client->start();
       talk_to_client::ptr new_client = talk_to_client::new_();
       acceptor.async_accept(new_client->sock(),
                             boost::bind(handle_accept,new_client,_1));
   }
   int main(int argc, char* argv[]) {
       talk_to_client::ptr client = talk_to_client::new_();
       acceptor.async_accept(client->sock(),boost::bind(handle_accept,client,_1));
    service.run();
}
上述代码会一直异步地等待一个新的client连接(每一个新的client连接会触发另外一个异步等待操作)。

我们须要监控client list changed事件(一个新client连接或者一个client断开连接),然后当事件发生时通知全部的client。因此,我们须要保存一个client连接的数组,否则。除非你不须要在某一时刻知道全部连接的client,你才不须要这样一个数组。
class talk_to_client; typedef boost::shared_ptr<talk_to_client>
   client_ptr;
   typedef std::vector<client_ptr> array;
   array clients;
connection类的框架例如以下:

class talk_to_client : public boost::enable_shared_from_this<talk_to_

client>

                        , boost::noncopyable {
       talk_to_client() { ... }
   public:
       typedef boost::system::error_code error_code;
       typedef boost::shared_ptr<talk_to_client> ptr;
       void start() {
           started_ = true;
           clients.push_back( shared_from_this());
           last_ping = boost::posix_time::microsec_clock::local_time();
           do_read(); //首先,我们等待客户端连接
       }
       static ptr new_() { ptr new_(new talk_to_client); return new_; }
       void stop() {
           if ( !started_) return;
           started_ = false;
           sock_.close();
           ptr self = shared_from_this();
           array::iterator it = std::find(clients.begin(), clients.end(),
   self);
           clients.erase(it);
           update_clients_changed();
       }
       bool started() const { return started_; }
       ip::tcp::socket & sock() { return sock_;}
       std::string username() const { return username_; }
       void set_clients_changed() { clients_changed_ = true; }
       … 
private:
       ip::tcp::socket sock_;
       enum { max_msg = 1024 };
       char read_buffer_[max_msg];
       char write_buffer_[max_msg];
       bool started_;
       std::string username_;
       deadline_timer timer_;
       boost::posix_time::ptime last_ping;
       bool clients_changed_;

};

我会用talk_to_client或者talk_to_server来调用connection类,从而使你更明确我所说的内容。
如今你须要用到之前的代码了;它和我们在client应用中所用到的是一样的。可是我们还有另外一个stop()方法,这种方法用来从client数组中移除一个client连接。

服务端持续不断地等待异步的read操作:
void on_read(const error_code & err, size_t bytes) {
       if ( err) stop();
       if ( !started() ) return;
       std::string msg(read_buffer_, bytes);
       if ( msg.find("login ") == 0) on_login(msg);
       else if ( msg.find("ping") == 0) on_ping();
       else if ( msg.find("ask_clients") == 0) on_clients();
   }
   void on_login(const std::string & msg) {
       std::istringstream in(msg);
       in >> username_ >> username_;
       do_write("login ok\n");
       update_clients_changed();
   }
   void on_ping() {
       do_write(clients_changed_ ? "ping client_list_changed\n" : "ping
   ok\n");
       clients_changed_ = false;
   }
void on_clients() {
    std::string msg;
for(array::const_iterator b =clients.begin(),e =clients.end(); b
   != e; ++b)
           msg += (*b)->username() + " ";
       do_write("clients " + msg + "\n");

这段代码是简单易懂的;须要注意的一点是:当一个新客户端登录,我们调用update_clients_changed(),这种方法为全部客户端将clients_changed_标志为true。

服务端每收到一个请求就用正确的方式进行回复。例如以下所看到的:
void do_ping() { do_write("ping\n"); }
   void do_ask_clients() { do_write("ask_clients\n"); }
   void on_write(const error_code & err, size_t bytes) { do_read(); }
   void do_read() {
       async_read(sock_, buffer(read_buffer_),
                   MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2));
       post_check_ping();
   }
   void do_write(const std::string & msg) {
       if ( !started() ) return;
       std::copy(msg.begin(), msg.end(), write_buffer_);
       sock_.async_write_some( buffer(write_buffer_, msg.size()),
                               MEM_FN2(on_write,_1,_2));
   }
   size_t read_complete(const boost::system::error_code & err, size_t
   bytes) {
       // ... as before
   }
在每一个write操作的末尾,on_write()方法被调用。这种方法会触发另外一个异步读操作,这种话“等待请求-回复请求”这个循环酒会一直运行,直到client断开连接或者超时。
在每次读操作開始之前,我们异步等待5秒钟来观察client是否超时。假设超时。我们关闭它的连接:
void on_check_ping() {
       ptime now = microsec_clock::local_time();
       if ( (now - last_ping).total_milliseconds() > 5000)
           stop();
       last_ping = boost::posix_time::microsec_clock::local_time();
   }
   void post_check_ping() {
       timer_.expires_from_now(boost::posix_time::millisec(5000));
       timer_.async_wait( MEM_FN(on_check_ping));
   }
这就是整个服务端的实现。你能够执行并让它工作起来!
在代码中,我向你们展示了这一章我们学到的东西,为了更easy理解,我把代码略微精简了下。比方,大部分的控制台输出我都没有展示。虽然在这本书附赠的代码中它们是存在的。

我建议你自己执行这些样例,由于从头到尾读一次代码能加强你对本章展示应用的理解。

总结
我们已经学到了怎么写一些基础的client/服务端应用。

我们已经避免了一些诸如内存泄漏和死锁的低级错误。全部的编码都是框架式的。这样你就能够依据你自己的需求对它们进行扩展。

在接下来的章节中,我们会更加深入地了解使用Boost.Asio进行同步编程和异步编程的不同点。同一时候你会也学会怎样嵌入你自己的异步操作。







本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5306409.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
C++ 用libcurl库进行http通讯网络编程
目录索引: 一、LibCurl基本编程框架 二、一些基本的函数 三、curl_easy_setopt函数部分选项介绍 四、curl_easy_perform 函数说明(error 状态码) 五、libcurl使用的HTTP消息头六、获取http应答头信息 七、多线程问题 八、什么时候libcurl无法正常工作 九、关于密码 十、HTTP验证 十一、代码示例 1.
1559 0
C++网络编程笔记
环境准备 codeblocks 1 Settings–Compiler–Linker Settings中添加~\CodeBlocks\MinGW\lib\libwsock32.a 2 #include &lt;winsock2.h&gt; vs2010 #include &lt;winsock2.h&gt; #pragma comment(lib, "ws2
764 0
【C/C++学院】(29)网络编程--实现跨平台传输文件(TCP版)
<p><span style="font-size:24px"><a target="_blank" href="http://download.csdn.net/detail/waldmer/8551223">网络编程--实现跨平台传输文件(TCP版)源码下载地址</a></span><br></p> <p><span style="font-family:'Microsoft YaH
2237 0
基于TCP/IP协议的C++网络编程(API函数版)
源代码:http://download.csdn.net/detail/nuptboyzhb/4169959 基于TCP/IP协议的网络编程 定义变量——获得WINSOCK版本——加载WINSOCK库——初始化——创建套接字 ——设置套接字选项——关闭套接字——卸载WINSOCK库——释放所有资源 整个程序架构分为两大部分,服务器端客户端。
1310 0
C++学习之从C到C++
C++学习之从C到C++
0 0
HLS开发学习-07- Vivado HLS 中的 C++ 基本运算
HLS开发学习-07- Vivado HLS 中的 C++ 基本运算
0 0
从c++到Java,关于Java面向对象基础的学习(二)
继续补充完成java面向基础对象学习的第二部分,本章内容主要包括构造器和this以及javabean和封装等思想,感觉仍然需要更多练习才能帮助熟练java面向对象基础部分
0 0
从c++到Java,关于Java面向对象基础的学习(一)
目录 一、设计对象并使用 1、学习获取已有对并使用学 2、学习如何自己设计对象并使用 3、定义类的补充注意事项 二、面向对象内存机制 1、多个对象内存图 2、两个变量指向同一个对象内存图 3、补充(垃圾回收)
0 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
使用C++开发PHP7扩展
立即下载
C++课程-对象模型
立即下载
继承与功能组合
立即下载