• 基于c++11新标准开发一个支持多线程高并发的网络库


    背景

            新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间。

    之前我也写过基于ACE的网络server框架,但ACE毕竟有些臃肿。内部对象关系错综复杂,easy给人造成仅仅见树木不见森林的错觉。 所以打算用c++11开发一个较为简洁,高效,支持高并发的网络库。

    开源

            基础的结构已经开发完毕,代码也开源在github上。网址是 https://github.com/lichuan/fly 欢迎各位提出建议。

    结构

            fly网络库主要分为base模块,task模块,net模块。base主要是一些最基础的功能集合。包含日志。id分配器,随机数,队列等。task主要封装了任务抽象以及任务调度运行等功能;net主要是实现网络层面的封装。为上层使用者提供简单易用的网络接口,这也是fly库的核心模块。实现了解析协议的Parser封装,负责监听网络的Acceptor,负责网络连接io功能的Poller封装体,在Parser、Acceptor、和Poller的基础上还进一步封装了作为server来使用的Server类和作为client来使用的Client类,这两个类是fly库的核心类,上层的应用能够直接使用Server对象和Client对象来建立网络server。作为网络连接概念的Connection对象则是通过std::shared_ptr来管理它的生命周期的,shared_ptr内置共享对象的功能大大地简化了网络连接生命期的管理。

    协议

            fly库的网络协议基于全世界最通用的json格式。而它的解析则依赖于rapidjson第三方库来完毕。

            协议组成例如以下:

            |长度字段|{协议类型:类型值,协议命令:命令值,其它json字段}|

            协议类型和协议命令组成了二级消息字,就能够组合出各种约定的协议了。

    应用

            fly库的test文件夹提供了一个简单的例程。当中test_server.cpp代码例如以下:

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *                    _______    _                                     *
     *                   (  ____   (      |     /|                      * 
     *                   | (    /  | (     (    / )                      *
     *                   | (__      | |       (_) /                       *
     *                   |  __)     | |          /                        *
     *                   | (        | |        ) (                         *
     *                   | )        | (____/  | |                         *
     *                   |/         (_______/  \_/                         *
     *                                                                     *
     *                                                                     *
     *     fly is an awesome c++11 network library.                        *
     *                                                                     *
     *   @author: lichuan                                                  *
     *   @qq: 308831759                                                    *
     *   @email: 308831759@qq.com                                          *
     *   @github: https://github.com/lichuan/fly                           *
     *   @date: 2015-06-10 13:34:21                                        *
     *                                                                     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    
    #include <unistd.h>
    #include <unordered_map>
    #include "fly/init.hpp"
    #include "fly/net/server.hpp"
    #include "fly/base/logger.hpp"
    
    using namespace std::placeholders;
    
    class Test_Server : public fly::base::Singleton<Test_Server>
    {
    public:
        bool allow(std::shared_ptr<fly::net::Connection> connection)
        {
            return true;
        }
        
        void init(std::shared_ptr<fly::net::Connection> connection)
        {
            std::lock_guard<std::mutex> guard(m_mutex);
            m_connections[connection->id()] = connection;
            LOG_INFO("connection count: %u", m_connections.size());
        }
        
        void dispatch(std::unique_ptr<fly::net::Message> message)
        {
            std::shared_ptr<fly::net::Connection> connection = message->get_connection();
            const fly::net::Addr &addr = connection->peer_addr();
            LOG_INFO("recv message from %s:%d raw_data: %s", addr.m_host.c_str(), addr.m_port, message->raw_data().c_str());
        }
        
        void close(std::shared_ptr<fly::net::Connection> connection)
        {
            LOG_INFO("close connection from %s:%d", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
            std::lock_guard<std::mutex> guard(m_mutex);
            m_connections.erase(connection->id());
            LOG_INFO("connection count: %u", m_connections.size());
        }
        
        void be_closed(std::shared_ptr<fly::net::Connection> connection)
        {
            LOG_INFO("connection from %s:%d be closed", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
            std::lock_guard<std::mutex> guard(m_mutex);
            m_connections.erase(connection->id());
            LOG_INFO("connection count: %u", m_connections.size());
        }
        
        void main()
        {
            //init library
            fly::init();
            
            //init logger
            fly::base::Logger::instance()->init(fly::base::DEBUG, "server", "./log/");
            
            //test tcp server
            std::unique_ptr<fly::net::Server> server(new fly::net::Server(fly::net::Addr("127.0.0.1", 8899),
                                                                          std::bind(&Test_Server::allow, this, _1),
                                                                          std::bind(&Test_Server::init, this, _1),
                                                                          std::bind(&Test_Server::dispatch, this, _1),
                                                                          std::bind(&Test_Server::close, this, _1),
                                                                          std::bind(&Test_Server::be_closed, this, _1)));
    
            if(server->start())
            {
                LOG_INFO("start server ok!");
                server->wait();
            }
            else
            {
                LOG_ERROR("start server failed");
            }
        }
        
    private:
        std::unordered_map<uint64, std::shared_ptr<fly::net::Connection>> m_connections;
        std::mutex m_mutex;
    };
    
    int main()
    {
        Test_Server::instance()->main();
    }

            Server对象构造时会要求传入监听地址和回调函数,当Server对象start启动时,fly库底层就会建立对应的Poller、Parser、Acceptor对象,假设想实现多线程Poller和Parser,则需传入并发线程数量就可以,回调函数说明例如以下:

            allow_cb:当有新的连接到达时调用。来推断是否同意该连接的注冊。

            init_cb:当把连接对象注冊到某一个Poller和Parser后调用,进行初始化处理。

            dispatch_cb:当有消息到达时会调用,进行消息派发。

            close_cb:主动关闭连接对象时调用。

            be_closed_cb:检測到对端关闭连接对象时调用。

            test_client.cpp主要使用Client对象来连接到某一个server,相同Client构造时也须要传入回调函数,其作用与Server构造时传入的回调一样。

  • 相关阅读:
    android代码签名和混乱的包装
    C# 中对WinForm窗体中的控件快速设置TableIndex次序
    常用的Oracle数据库语句 (待更新完毕)
    [转] C# 键盘中的按键对应的KeyValue
    Oracle 数据库中日期时间的插入操作
    C#操作Excel,对Sheet插入次序的控制 (有待完善)
    Simditor图片上传
    文件类似的推理 -- 超级本征值(super feature)
    leetcode 名单 Insertion Sort List
    汉高澳大利亚sinox2014电影播放flash最好的办法是安装游戏windows文本firefox
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/6772693.html
Copyright © 2020-2023  润新知