• 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:
    valid links: " size_t_format ", closed links: " size_t_format "
    ",  
    
                    server_.size(), server_.closed_object_size());  
    
                printf("echo server:
    valid links: " size_t_format ", closed links: " size_t_format "
    ",  
    
                    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,请参看教程第四篇

  • 相关阅读:
    nginx 主配置文件解析
    redis 主从同步
    redis 持久化 RDB与AOF
    python开发之virtualenv与virtualenvwrapper(linux下安装与配置)
    linux 编译安装python3
    linux基础系统优化及常用命令
    linux基础
    以太坊源码之POA区块生成机制
    以太坊Go、Java、Python、Ruby、JS客户端介绍
    区块链扫盲:区块链技术初探(一)
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4254738.html
Copyright © 2020-2023  润新知