Handy是一個簡潔優雅的C++11網絡庫,適用於linux與Mac平台。十行代碼即可完成一個完整的網絡服務器。
下面是echo服務器的代碼:
#include <handy/handy.h> using namespace std; using namespace handy; int main(int argc, const char* argv[]) { EventBase bases; //事件分發器 Signal::signal(SIGINT, [&]{ bases.exit(); }); //注冊Ctrl+C的信號處理器--退出事件分發循環 TcpServer echo(&bases); //創建服務器 int r = echo.bind("", 99); //綁定端口 exitif(r, "bind failed %d %s", errno, strerror(errno)); echo.onConnRead([](const TcpConnPtr& con) { con->send(con->getInput()); // echo 讀取的數據 }); bases.loop(); //進入事件分發循環 }
其中EventBase是事件分發器,內部使用epoll/kqueue進行IO事件分發。
EventBase功能豐富,還包含了定時任務等功能。
網絡編程中全異步處理請求的難度較高,特別是涉及業務邏輯,涉及數據庫使用等情況。大家使用的最常見的模型是用異步處理IO,保證大的並發量,使用多線程處理業務請求,簡化業務邏輯的編寫。這種半同步半異步的編程模型我們簡稱為HSHA(half sync half async)。
Handy能夠支持HSHA,下面是一個完整的服務器例子:
#include <handy/handy.h>
using namespace std;
using namespace handy;
int main(int argc, const char* argv[]) {
EventBase base;
HSHA hsha(&base, 4); //啟動4個線程進行同步處理
int r = hsha.bind("", 99);
exitif(r, "bind failed");
//注冊Ctrl+C的信號處理
Signal::signal(SIGINT, [&]{ 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
