10行代碼編寫一個c++服務器

Handy是一個簡潔優雅的C++11網絡庫,適用於linux與Mac平臺。十行代碼即可完成一個完整的網絡服務器。


下面是echo服務器的代碼:


#include <handy/handy.h>
using namespace handy;


int main(int argc, const char* argv[]) {
    EventBase base;
    Signal::signal(SIGINT, [&]{ base.exit(); });
    TcpServerPtr svr = TcpServer::startServer(&base, "", 99);
    exitif(svr == NULL, "start tcp server failed");
    svr->onConnRead([](const TcpConnPtr& con) {
        con->send(con->getInput());
    });
    base.loop();
}


其中EventBase是事件分發器,內部使用epoll/kqueue進行IO事件分發。

EventBase功能豐富,還包含了定時任務等功能。

網絡編程中全異步處理請求的難度較高,特別是涉及業務邏輯,涉及數據庫使用等情況。大家使用的最常見的模型是用異步處理IO,保證大的併發量,使用多線程處理業務請求,簡化業務邏輯的編寫。這種半同步半異步的編程模型我們簡稱爲HSHA(half sync half async)。

Handy能夠支持HSHA,下面是一個完整的服務器例子:

#include <handy/handy.h>
using namespace handy; 

int main(int argc, const char* argv[]) {
    EventBase base;
    HSHAPtr hsha = HSHA::startServer(&base, "", 99, 4); //啓動4個線程進行同步處理
    exitif(!hsha, "hsha startServer failed");
   //註冊Ctrl+C的信號處理
    Signal::signal(SIGINT, [&, hsha]{ base.exit(); hsha->exit(); signal(SIGINT, SIG_DFL);});

   // 消息處理函數
    hsha->onMsg(new LineCodec, [](const TcpConnPtr& con, const string& input){
        int ms = rand() % 1000;
        info("processing a msg");
        usleep(ms * 1000);
        return util::format("%s used %d ms", input.c_str(), ms);
    });
    base.loop();
}

其中onMsg註冊消息處理函數,onMsg的第一個參數爲消息解碼器,該解碼器把tcp連接的輸入字節流解碼爲一個個消息,對每個完整的消息調用onMsg傳入的第二個cb參數。

cb參數的原型爲string cb (const TcpConnPtr& con, const string& input),用戶只需要編寫這個cb函數,處理輸入,返回處理結果即可。cb函數在線程池中調用,因此處理函數中的sleep等操作不會堵塞網絡IO。上述例子中,用戶可以使用telnet登陸到這個hsha例子服務器上,發送消息給服務器,服務器端的日誌裏可以發現輸出‘processing a msg’的線程並非IO線程。

如果用戶需要更加靈活的處理,可以返回空字符串表示未處理完,可以直接操作con這個連接。

Handy還具備更多的功能,如定時處理,清理空閒連接等等,詳情參見https://github.com/yedf/handy
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章