我正在使用C ++开发服务器应用程序。我设计的方式是主要进程,负责维护子进程( worker )。工人accept()
新连接并创建线程以便单独处理它们。
假设我在主进程中创建一个侦听器套接字,并且每个 worker 将监视它(使用kqueue,epoll等)以进行新连接。经过一番研究后,我发现了一些肯定,即需要在侦听器套接字上使用mutex
来防止并发accept()
,这会导致工作人员accept()
同时连接相同的连接。
嗯,意识到这种需求,我不确定在工作人员之间分配客户连接的最佳方式是什么,因为结果与accept()
相同他们在主进程中以某种方式将新套接字FD发送给工作人员(新连接处理变为阻塞 - 一次只有一个accept()
。
我的问题是:真的需要在侦听套接字上mutex
吗?我对accept()
阻止(一次一个新连接accept()
)副作用是对吗?
我担心这个单一的细节,因为这个应用程序必须每秒扩展到数千个新连接(具体数量可能会有所不同,因为此应用程序旨在用于具有100到1000个客户端的网络)。
答案 0 :(得分:3)
很久以前,如果多个进程在同一个套接字上同时执行accept
,那么操作系统会遇到竞争条件。 Apache曾经有一个可选的接受互斥来解决这个问题。
此问题早已在您可能使用的每个操作系统上得到解决,并且使用工作人员呼叫accept
的共享套接字是完全合理的。如果您希望每个工作程序一次只处理一个连接,则空闲工作程序可以在共享套接字上阻塞accept
。
我担心这个单一细节,因为这个应用程序必须每秒扩展到数十万甚至数百万个新连接。我想避免编写两个复杂应用程序的工作,其唯一目的是比较两种方法的性能。此外,我无法模拟真实世界的同步连接。
你不能双管齐下。要么你放弃这样雄心勃勃的扩展计划,要么你接受你将有许多重大的努力。只是模拟这种连接负载进行测试将是一项重大工作。
答案 1 :(得分:-2)
我无法回答关于listen()和accept()调用的线程安全问题的部分问题,因为我甚至都不会考虑尝试。我要做的是让主线程执行listen()和accept(),并在accept()返回时分叉一个新线程,将套接字传递给线程。
类似地,您可以拥有一堆正在运行的线程,并且互斥一个将执行套接字通知的变量。基本上与上面相同,但不是在接受时创建线程,而是通知已经运行的套接字描述符线程。一般伪代码可能是:
main()
{
listen();
while(true)
{
int socket = accept();
if(fork() == 0)
{
DoMyThing(socket);
}
}
}