程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 基於c++11新標准開發一個支持多線程高並發的網絡庫

基於c++11新標准開發一個支持多線程高並發的網絡庫

編輯:關於C++

背景

新的c++11標准出後,c++語法得到了很多的擴展,比起以往任何時候都要靈活和高效,提高了程序編碼的效率,為軟件開發人員節省了不少的時間。 之前我也寫過基於ACE的網絡服務器框架,但ACE畢竟有些臃腫,內部對象關系錯綜復雜,容易給人造成只見樹木不見森林的錯覺。 所以打算用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類和作為客戶端來使用的Client類,這兩個類是fly庫的核心類,上層的應用可以直接使用Server對象和Client對象來建立網絡服務器。作為網絡連接概念的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: [email protected]                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-10 13:34:21                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include 
#include 
#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
{
public:
    bool allow(std::shared_ptr connection)
    {
        return true;
    }
    
    void init(std::shared_ptr connection)
    {
        std::lock_guard guard(m_mutex);
        m_connections[connection->id()] = connection;
        LOG_INFO(connection count: %u, m_connections.size());
    }
    
    void dispatch(std::unique_ptr message)
    {
        std::shared_ptr 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 connection)
    {
        LOG_INFO(close connection from %s:%d, connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
        std::lock_guard guard(m_mutex);
        m_connections.erase(connection->id());
        LOG_INFO(connection count: %u, m_connections.size());
    }
    
    void be_closed(std::shared_ptr connection)
    {
        LOG_INFO(connection from %s:%d be closed, connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
        std::lock_guard 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 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> 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對象來連接到某一個服務器,同樣Client構造時也需要傳入回調函數,其作用與Server構造時傳入的回調一樣。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved