我正在尝试用 C 语言编写一个能够同时处理多个(超过一千个)客户端连接的服务器。每个连接都旨在完成三件事:
- 向服务器发送数据
- 服务器处理数据
- 服务器返回数据给客户端
我正在使用非阻塞套接字和 epoll() 来处理所有连接,但我的问题是在服务器从一个客户端接收数据并且必须调用一个函数后的那一刻,该函数花费几秒钟来处理返回结果之前的数据必须在关闭连接之前发送回客户端。
我的问题是,我可以使用什么范式来在一个客户端的数据“正在处理”时继续处理更多的连接?
我一直在研究通过每次都创建一个线程或进程来实现它的可能性我需要调用计算函数,但我不确定这是否会考虑到可能的并发连接数量,这是可能的,这就是为什么我来到这里,希望有人在这件事上比我更有经验,可以阐明我的无知。
代码片段:
while (1)
{
ssize_t count;
char buf[512];
count = read (events[i].data.fd, buf, sizeof buf); // read the data
if (count == -1)
{
/* If errno == EAGAIN, that means we have read all
data. So go back to the main loop. */
if (errno != EAGAIN)
{
perror ("read");
done = 1;
}
/* Here is where I should call the processing function before
exiting the loop and closing the actual connection */
answer = proc_function(buf);
count = write (events[i].data.fd, answer, sizeof answer); // send the answer to the client
break;
}
...
提前致谢。
最佳答案
多线程或多进程在某种程度上实现这一点似乎是明智的。问题是多线程或多进程的程度。
1) 您可以完全转储轮询系统并为每个连接使用一个线程/进程。只要该线程想要处理该连接,它就可以停止。然后,您必须决定是每次创建/终止一个线程/进程(可能最简单)还是拥有一个线程/进程池(可能最快)。
2) 您可以为网络位创建一个线程/进程,然后将处理移交给另一个线程。这不太并行,但它确实意味着您至少可以在处理工作列表时继续处理网络连接。这使您至少可以控制正在处理的过程。以这种方式确定传入连接的优先级很容易,而选项 1 可能不会。
3)(可能是 1 和 2)您可以使用异步 I/O 来多路复用您的连接。你还是按照上面1&2一样的方式处理。
您还有线程与进程的问题。线程可能运行起来更快,但更难确保数据完整性。流程将更具弹性,但它们之间需要更多的接口(interface)。
您还必须决定在线程/进程之间传递数据的方式。这对于选项 1 来说不是什么问题,因为您只需要传递与线程的连接。选项 2 可能(取决于您的数据是什么)问题更大。您可以使用消息队列来传递有关的消息,但如果您有大量数据,则发送共享内存更为合适。共享内存对于进程来说是一件痛苦的事情,但对于线程来说却很容易(因为所有线程共享相同的内存空间)。
达到这种规模时也会出现性能问题。值得研究这些东西的性能特征。当您处理大量连接时,select 和 poll 等调用的规模差异很大。
如果不知道发送和接收的数据是什么,就很难给出可靠的建议。
顺便说一下,这不是一个新问题。 Dan Kegel有一个good article关于它几年前。它现在已经过时了,但概述仍然很好。不过,您应该研究他所讨论概念的最新技术水平。
关于同时计算来自多个客户端的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17573422/