基于協(xié)程和事件循環(huán)的c++網(wǎng)絡(luò)庫
完整資料進(jìn)入【數(shù)字空間】查看——baidu搜索"writebug"
## 介紹
開發(fā)服務(wù)端程序的一個基本任務(wù)是處理并發(fā)連接,現(xiàn)在服務(wù)端網(wǎng)絡(luò)編程處理并發(fā)連接主要有兩種方式:
1. 當(dāng)“線程”很廉價時,一臺機(jī)器上可以創(chuàng)建遠(yuǎn)高于CPU數(shù)目的“線程”。這時一個線程只處理一個TCP連接,通常使用阻塞IO。例如Go goroutine。這里的“線程”由語言的runtime自行調(diào)度。
2. 當(dāng)線程很寶貴時,一臺機(jī)器上只能創(chuàng)建與CPU數(shù)目相當(dāng)?shù)木€程。這時一個線程要處理多個TCP連接上的IO,通常使用非阻塞IO和IO multiplexing。C++編程主要采用這種方式。
在線程很寶貴的情況下,常見的服務(wù)器編程模型有如下幾種:
1. 每個請求創(chuàng)建一個線程,使用阻塞式IO操作(或者叫thread per connection)。這種模型的優(yōu)點(diǎn)是可以使用阻塞操作,缺點(diǎn)是伸縮性不強(qiáng),每臺機(jī)器能創(chuàng)建的線程是有限的,32位的機(jī)器應(yīng)該不超過400個。
2. 非阻塞IO+IO多路復(fù)用(或者叫one loop per thread或者Reactor)+ 線程池。
melon是基于Reactor模式的Linux C++網(wǎng)絡(luò)服務(wù)框架,集合了上述兩種方式,實(shí)現(xiàn)了協(xié)程的概念,對一些函數(shù)進(jìn)行了hook,所以可以像操作阻塞IO一樣進(jìn)行編程。
## 使用
在工程主目錄下新建build目錄,進(jìn)入build目錄,
```text
cmake ..
make? all
```
編譯完成后,example和test中的可執(zhí)行程序分別位于build目錄下的example和test中。
以echo服務(wù)端為例,
```
void handleClient(TcpConnection::Ptr conn){
conn->setTcpNoDelay(true);
Buffer::Ptr buffer = std::make_shared<Buffer>();
while (conn->read(buffer) > 0) {
conn->write(buffer);
}
conn->close();
}
int main(int args, char* argv[]) {
if (args != 2) {
printf("Usage: %s threads\n", argv[0]);
return 0;
}
Logger::setLogLevel(LogLevel::INFO);
Singleton<Logger>::getInstance()->addAppender("console", LogAppender::ptr(new ConsoleAppender()));
IpAddress listen_addr(5000);
int threads_num = std::atoi(argv[1]);
Scheduler scheduler(threads_num);
scheduler.startAsync();
TcpServer server(listen_addr, &scheduler);
server.setConnectionHandler(handleClient);
server.start();
scheduler.wait();
return 0;
}
```
只需要為TcpServer設(shè)置連接處理函數(shù),在連接處理函數(shù)中,參數(shù)TcpConnection::Ptr conn代表此次連接,可以像阻塞IO一樣進(jìn)行讀寫,如果發(fā)生阻塞,當(dāng)前協(xié)程會被切出去,直到可讀或者可寫事件到來時,該協(xié)程會被重新執(zhí)行。





