欢迎光临散文网 会员登陆 & 注册

基于协程和事件循环的c++网络库

2023-07-18 10:11 作者:玟玟的大宝贝  | 我要投稿

完整资料进入【数字空间】查看——baidu搜索"writebug"


## 介绍


开发服务端程序的一个基本任务是处理并发连接,现在服务端网络编程处理并发连接主要有两种方式:


1. 当“线程”很廉价时,一台机器上可以创建远高于CPU数目的“线程”。这时一个线程只处理一个TCP连接,通常使用阻塞IO。例如Go goroutine。这里的“线程”由语言的runtime自行调度。

2. 当线程很宝贵时,一台机器上只能创建与CPU数目相当的线程。这时一个线程要处理多个TCP连接上的IO,通常使用非阻塞IO和IO multiplexing。C++编程主要采用这种方式。


在线程很宝贵的情况下,常见的服务器编程模型有如下几种:


1. 每个请求创建一个线程,使用阻塞式IO操作(或者叫thread per connection)。这种模型的优点是可以使用阻塞操作,缺点是伸缩性不强,每台机器能创建的线程是有限的,32位的机器应该不超过400个。

2. 非阻塞IO+IO多路复用(或者叫one loop per thread或者Reactor)+ 线程池。


melon是基于Reactor模式的Linux C++网络服务框架,集合了上述两种方式,实现了协程的概念,对一些函数进行了hook,所以可以像操作阻塞IO一样进行编程。


## 使用


在工程主目录下新建build目录,进入build目录,


```text

cmake ..

make  all

```


编译完成后,example和test中的可执行程序分别位于build目录下的example和test中。


以echo服务端为例,


```

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设置连接处理函数,在连接处理函数中,参数TcpConnection::Ptr conn代表此次连接,可以像阻塞IO一样进行读写,如果发生阻塞,当前协程会被切出去,直到可读或者可写事件到来时,该协程会被重新执行。



基于协程和事件循环的c++网络库的评论 (共 条)

分享到微博请遵守国家法律