boost.asio包装类st_asio_wrapper开发教程(2013.12.8更新)(二)

如果你是偶然浏览到这里,请先看 
源代码及例程下载地址:
命令行:svn checkout http://st-asio-wrapper.googlecode.com/svn/trunk/ st-asio-wrapper-read-only
如果从svn客户端界面上打开,则只输入http://st-asio-wrapper.googlecode.com/svn/trunk/到地址栏即可
git:https://github.com/youngwolf-project/st_asio_wrapper/,另外,我的资源里面也有下载,但不是最新的。
QQ交流群:198941541

六:开发教程(服务端)
服务端直接#include st_asio_wrapper_server.h,就可实现一个简单的服务端了,如下(还演示了一个echo服务器,所以继承st_server写了个echo_server类):

//configuration  

#define SERVER_PORT     9527  

#define REUSE_OBJECT //use objects pool  

//#define FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  

#define ENHANCED_STABILITY  

//configuration  

#include "st_asio_wrapper_server.h"  

using namespace st_asio_wrapper;  

#define QUIT_COMMAND    "quit"  

#define RESTART_COMMAND "restart"  

#define LIST_ALL_CLIENT "list_all_client"  

#define LIST_STATUS     "status"  

#define SUSPEND_COMMAND "suspend"  

#define RESUME_COMMAND  "resume"  

//demonstrate how to use custom packer  

//in the default behavior, every st_tcp_socket has their own packer, and cause memory waste  

//at here, we make every echo_socket use the same global packer for memory saving  

//notice: do not do this for unpacker, because unpacker has member variables and can‘t share each other  

auto global_packer(boost::make_shared<packer>());  

//demonstrates how to control the type of st_server_socket_base::server from template parameters  

class i_echo_server : public i_server  

{  

public:  

virtual void test() = 0;  

};  

class echo_socket : public st_server_socket_base<boost::asio::ip::tcp::socket, i_echo_server>  

{  

public:  

    echo_socket(i_server& server_) : st_server_socket_base(server_) {inner_packer(global_packer);}  

public:  

//because we use objects pool(REUSE_OBJECT been defined), so, strictly speaking, this virtual  

//function must be rewrote, but we don‘t have member variables to initialize but invoke father‘s  

//reset() directly, so, it can be omitted, but we keep it for possibly future using  

virtual void reset() {st_server_socket_base::reset();}  

protected:  

virtual void on_recv_error(const error_code& ec)  

    {  

//the type of st_server_base::server now can be controled by derived class(echo_socket),  

//which is actually i_echo_server, so, we can invoke i_echo_server::test virtual function.  

        server.test();  

        st_server_socket_base::on_recv_error(ec);  

    }  

//msg handling: send the original msg back(echo server)  

#ifndef FORCE_TO_USE_MSG_RECV_BUFFER  

//this virtual function doesn‘t exists if FORCE_TO_USE_MSG_RECV_BUFFER been defined  

virtual bool on_msg(msg_ctype& msg) {post_msg(msg); return false;}  

#endif  

//we should handle the msg in on_msg_handle for time-consuming task like this:  

virtual void on_msg_handle(msg_ctype& msg) {post_msg(msg);}  

//please remember that we have defined FORCE_TO_USE_MSG_RECV_BUFFER, so, st_tcp_socket will directly  

//use the msg recv buffer, and we need not rewrite on_msg(), which doesn‘t exist any more  

//msg handling end  

};  

class echo_server : public st_server_base<echo_socket, st_object_pool<echo_socket>, i_echo_server>  

{  

public:  

    echo_server(st_service_pump& service_pump_) : st_server_base(service_pump_) {}  

//from i_echo_server, pure virtual function, we must implement it.  

virtual void test() {/*puts("in echo_server::test()");*/}  

};  

int main() {  

    puts("type quit to end these two servers.");  

    std::string str;  

    st_service_pump service_pump;  

    st_server server_(service_pump); //only need a simple server? you can directly use st_server  

    server_.set_server_addr(SERVER_PORT + 100);  

    echo_server echo_server_(service_pump); //echo server  

    service_pump.start_service(1);  

while(service_pump.is_running())  

    {  

        std::cin >> str;  

if (str == QUIT_COMMAND)  

            service_pump.stop_service();  

else if (str == RESTART_COMMAND)  

        {  

            service_pump.stop_service();  

            service_pump.start_service(1);  

        }  

else if (str == LIST_STATUS)  

        {  

            printf("normal server:\nvalid links: " size_t_format ", closed links: " size_t_format "\n",  

                server_.size(), server_.closed_object_size());  

            printf("echo server:\nvalid links: " size_t_format ", closed links: " size_t_format "\n",  

                echo_server_.size(), echo_server_.closed_object_size());  

        }  

//the following two commands demonstrate how to suspend msg dispatching, no matter recv buffer been used or not  

else if (str == SUSPEND_COMMAND)  

            echo_server_.do_something_to_all(boost::bind(&echo_socket::suspend_dispatch_msg, _1, true));  

else if (str == RESUME_COMMAND)  

            echo_server_.do_something_to_all(boost::bind(&echo_socket::suspend_dispatch_msg, _1, false));  

else if (str == LIST_ALL_CLIENT)  

        {  

            puts("clients from normal server:");  

            server_.list_all_object();  

            puts("clients from echo server:");  

            echo_server_.list_all_object();  

        }  

else  

            server_.broadcast_msg(str);  

        }  

return 0;  

}  

//restore configuration  

#undef SERVER_PORT  

#undef REUSE_OBJECT //use objects pool  

//#undef FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  

#undef ENHANCED_STABILITY  

//restore configuration  

以上例子中,服务端从控制台接收数据,调用broadcast_msg广播数据;当收到数据时,会输出到控制台(st_tcp_socket实现);

其中st_server server_;这行申请了一个普通的服务端,它的功能仅仅是发送接收消息,接受连接。一般来说,就像教程一里面的客户端一样,需要从st_server_socket继承一个自己的套接字类,从st_server继承一个服务类。为此,服务端demo还演示了一个echo服务器,它会把收到的任何数据发送回去(大家可以学着做一个echo客户端,但不要echo服务端与echo客户端一同工作,否则就死循环了。
        start_service开启服务,stop_service结束服务(退出时必须明确调用),is_running判断服务的运行状态;如果想修改服务端地址,则在调用start_service之前调用set_server_addr函数;
        stop_service之后,可再次调用start_service开启服务;
        注意:st_server的del_client一般用于服务端被动删除某个client(即在错误发生的时候,比如在st_tcp_socket的on_recv_error和on_send_error里面调用,参看st_server_socket);服务端如果想主动关闭某个client,建议调用这个client的force_close或者graceful_close(st_tcp_socket实现)函数,它们的调用最终会促使on_recv_error的调用;
        st_server的close_all_client主动关闭所有client,比如服务端退出的时候(stop_service会自动调用);
        重写st_server的on_accept函数,根据你自己的策略确定是否接受客户端的连接,接受返回true;
        st_server的维护了一个链表(st_object_pool实现)用于保存所有的client(这样带几个好处:一、在广播消息的时候,很方便;二、可开启类似垃圾回收机制的自动清理已经关闭的连接的功能;三、可开启对象池功能),如果你想自己管理这些client,可以在on_accept里面返回false,然后把它保存在自己的容器里面,并调用start(st_server_socket实现)以便开始接受数据(只调用一次即可);
        当然,你还可以在返回true的同时,自己也保存一份client(此时就不要再调用start了),这样做不会带来多少内存消耗,因为它是用智能指针包装的,复制一份只是增加一个引用计数。至于这样做有什么好处,如果你想不到,说明你不需要,当你有需求的时候,你自然而然就会知道有什么用了,我在这里只是告诉大家可以这样做,有个印象即可;
        关于是重写on_msg还是on_msg_handle,请参看教程第四篇

时间: 2024-10-10 14:40:03

boost.asio包装类st_asio_wrapper开发教程(2013.12.8更新)(二)的相关文章

boost.asio包装类st_asio_wrapper开发教程(2014.5.23更新)(一)-----转

一:什么是st_asio_wrapper它是一个c/s网络编程框架,基于对boost.asio的包装(最低在boost-1.49.0上调试过),目的是快速的构建一个c/s系统:二:st_asio_wrapper的特点效率高.跨平台.完全异步,当然这是从boost.asio继承而来:自动重连,数据透明传输,自动解决分包粘包问题(必须使用默认的打包解包器,这一特性表现得与udp一样):只支持tcp和udp协议:三:st_asio_wrapper的大体结构st_asio_wrapper.h:编译器版本

boost.asio包装类st_asio_wrapper开发教程(一)

一:什么是st_asio_wrapper它是一个c/s网络编程框架,基于对boost.asio的包装(最低在boost-1.49.0上调试过),目的是快速的构建一个c/s系统: 二:st_asio_wrapper的特点效率高.跨平台.完全异步,当然这是从boost.asio继承而来:自动重连,数据透明传输,自动解决分包粘包问题(必须使用默认的打包解包器,这一特性表现得与udp一样):只支持tcp和udp协议: 三:st_asio_wrapper的大体结构st_asio_wrapper.h:编译器

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

异步run(), run_one(), poll(), poll_ one() 为了实现监听循环,io_service类提供了4个方法,比如:run(), run_one(), poll()和poll_one().当大部分时间你使用service.run()就可以.你会在这里学习到其他方法完成了什么. 持续运行 再一次说明,如果有等待执行的操作,run()会一直执行,直到你手动调用io_service::stop().为了保证io_service一直执行,通常你添加一个或者多个异步操作,然后当它

微信公众帐号开发教程第12篇-符号表情的发送(下)

第11篇文章给出了Unified版本的符号表情(emoji表情)代码表,并且介绍了如何在微信公众帐号开发模式下发送emoji表情,还在文章结尾出,卖了个关子:"小q机器人中使用的一些符号表情,在微信的符号表情选择栏里根本找不到,并且在上篇文章给出的符号表情代码表(Unified版)中也没有,那这些表情是如何发送的呢?"如下面两张图所示的符号表情"情侣"和"公共汽车".          本文主要介绍以下内容:1)如何在微信上使用更多的符号表情(即

Android快乐贪吃蛇游戏实战项目开发教程-03虚拟方向键(二)绘制一个三角形

该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.绘制三角形 在上一篇文章中,我们已经新建了虚拟方向键的自定义控件DirectionKeys类,下面我们继续. 本项目中的虚拟方向键的背景是4个三角形组成的矩形,其实是4个三角形的按钮. 系统自带的按钮是矩形的,怎么做一个三角形按钮呢? 首先我需要了解,所有控件的外观都是画出来的,当然不是我们手工去画而是用程序去画. 用程序怎么画呢? 很多技术平台上都有绘图功能,用起来也很相

MyEclipse WebSphere开发教程:安装和更新WebSphere 6.1, JAX-WS, EJB 3.0(七)

[周年庆]MyEclipse个人授权 折扣低至冰点!立即开抢>> [MyEclipse最新版下载] MyEclipse支持Java EE技术(如JAX-WS和EJB 3.0),它们以功能包的形式可用于WebSphere 6.1,但未开箱即用.本指南将引导您完成安装WebSphere 6.1.功能包和更新. 在本指南中,您将: 安装WebSphere 6.1和更新 在启动时禁用运行WebSphere的Windows系统服务 安装Web服务.EJB功能包和更新 管理您的个人资料 还没有MyEcli

Android开发教程 - 使用Data Binding(二)集成与配置

安装依赖库,配置工程 Data Binding安装和配置都非常简单,仅需简单的两步即可完成. 更新SDK 打开SDK管理工具,下载最新的Android Support库. 配置工程的Gradle android { - dataBinding { enabled = true } } 加入完成后,然后点击Sync Now,完成后就可以使用Data Binding强大的功能了. 总结 这一篇我们介绍了Data Binding的配置,下一篇我们将介绍在Activity中使用Data Binding的

boost.asio源码剖析(四) ---- asio中的泛型概念(concepts)

* Protocol(通信协议) Protocol,是asio在网络编程方面最重要的一个concept.在第一章中的levelX类图中可以看到,所有提供网络相关功能的服务和I/O对象都需要Protocol来确定一些细节. Protocol的约束摘要如下: 1 class protocol 2 { 3 public: 4 /// Obtain an identifier for the type of the protocol. 5 int type() const; 6 7 /// Obtain

boost asio one client one thread

总结了一个简单的boost asio的tcp服务器端与客户端通信流程.模型是一个client对应一个线程.先做一个记录,后续再对此进行优化. 环境:VS2017  + Boost 1.67 server: 1 #include <stdio.h> 2 #include <cstdlib> 3 #include <iostream> 4 #include <boost/thread.hpp> 5 #include <boost/aligned_stora