最近一直在学习socket编程,终于在Beej's Guide to Network Programming找到了一些很好的例子.
在poll
section 下有一个使用poll
的聊天服务器示例.
代码:
charsever.c (聊天服务器接收客户端消息并向所有其他客户端发送消息)
逐行阅读代码并完全理解示例后,我突然意识到设计的巧妙和整洁。
基本上,它使用轮询
来监视所有内容,服务器监听套接字accept
以获取新传入的TCP 连接和所有现有的TCP 套接字。不需要额外的线程或进程。
然后我开始问自己:
看来我可以使用多个进程(如果太复杂的话,也可以使用多个线程)来达到相同的效果。以聊天服务器为例,设计可以是:
- 主进程处理新传入的 TCP 连接并将新的连接套接字添加到全局数组
all_sockets
。 - 对于主进程中的每个新连接,
fork
一个要阻塞的子进程,这样写:
//pseudo-code
int bytes_from_client;
while(true){
if( (bytes_from_client = recv(xx,xx,xx,xx)) <= 0 ){
if(bytes_from_client == 0){
client_shutdown();
} else {
error_handle();
}
} else {
//recv data from client and send messages to all the other clients
for(int i = 0; i < all_sockets[x]; i++){
send(xx,xx,xx,xx);
}
}
}
- 好的,那么我需要处理一些全局变量的同步问题。使用
mutex
或其他东西。 (困难部分)
现在开始提问:
与我稍后描述的多线程模式相比,
poll
设计模式到底有什么好处?不需要处理同步?只有这1个优势?(一个更通用但有意义的问题)这种设计模式是由
poll
制作的,类似函数(select
、epoll
)让他们如此不同/独特和伟大? (我是新手所以问这个是因为看到很多人说poll
家族的函数有多么伟大和重要。但是他们从来不说为什么,也不举例,也不比较。)
最佳答案
一个简单的 select()
循环如此有效的一个基本原因是网络数据包总是一次一个地到达,与任何 CPU 的致盲速度相比,它非常慢.更复杂的安排根本没有任何优势。
通常,一个线程或进程专用于处理网络连接……轮询传入数据包并代表每个人发送传出消息。 (我听说它被称为“电报员”。)然后它使用队列将工作分配给稳定的“工蜂”进程,这些进程在一个队列上检索请求,然后将传出的答案发布到另一个队列,该队列也是被电报员收听了。
有时,电报员只是简单地监听连接请求,将句柄放在队列中,然后工蜂打开连接并自己进行网络连接。但是,再一次,他们可以简单地使用轮询,而且效果很好。即使是最快的通信线路也比 CPU 慢几个数量级。
关于c++ - 鉴于此示例,与使用多线程或进程相比,轮询设计对我有何好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58878749/