完整资料进入【数字空间】查看——baidu搜索"writebug"
介绍
开发服务端程序的一个基本任务是处理并发连接,现在服务端网络编程处理并发连接主要有两种方式:
-
当“线程”很廉价时,一台机器上可以创建远高于CPU数目的“线程”。这时一个线程只处理一个TCP连接,通常使用阻塞IO。例如Go goroutine。这里的“线程”由语言的runtime自行调度。
-
当线程很宝贵时,一台机器上只能创建与CPU数目相当的线程。这时一个线程要处理多个TCP连接上的IO,通常使用非阻塞IO和IO multiplexing。C++编程主要采用这种方式。
在线程很宝贵的情况下,常见的服务器编程模型有如下几种:
-
每个请求创建一个线程,使用阻塞式IO操作(或者叫thread per connection)。这种模型的优点是可以使用阻塞操作,缺点是伸缩性不强,每台机器能创建的线程是有限的,32位的机器应该不超过400个。
-
非阻塞IO+IO多路复用(或者叫one loop per thread或者Reactor)+ 线程池。
melon是基于Reactor模式的Linux C++网络服务框架,集合了上述两种方式,实现了协程的概念,对一些函数进行了hook,所以可以像操作阻塞IO一样进行编程。
使用
在工程主目录下新建build目录,进入build目录,
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一样进行读写,如果发生阻塞,当前协程会被切出去,直到可读或者可写事件到来时,该协程会被重新执行。