用C编写Linux服务器的最佳方法(phtreads,select或fork?)

时间:2012-04-02 14:40:35

标签: c++ c linux sockets

我有一个关于UNIX中服务器编程的非常具体的问题(Debian,内核2.6.32)。我的目标是学习如何编写可以处理大量客户端的服务器。我的目标是超过30 000个并发客户(即使我的大学提到有50万个可能,这似乎是QUIIITEEE的大量:-)),但我真的不知道(甚至可能是什么)这就是我要问的原因这里。所以我的第一个问题。有多少同时客户可能?客户端可以随时连接并与其他客户端联系并组成一个组(1个组最多包含12个客户端)。他们可以互相聊天,因此TCP / IP包的大小取决于发送的消息。 客户端还可以将数学公式发送到服务器。服务器将解决它们并将答案广播回组。这是一个非常繁重的操作。

我目前的做法是启动服务器。比使用fork创建一个守护进程。守护进程绑定套接字fd_listen并开始侦听。这是一个while(1)循环。我使用accept()来接听来电。

一旦客户端连接,我就为该客户端创建一个运行通信的pthread。客户端被添加到一个组并共享一些内存(需要保持组运行),但仍然每个客户端都在不同的线程上运行。获得正确的内存访问是一个很大的问题,但现在工作正常。

在程序的开头我读出/ proc / sys / kernel / threads-max文件并根据我创建我的线程。根据该文件的可能线程数量约为5000.远离我希望能够服务的客户端数量。 我考虑的另一种方法是使用select()和创建集。但是在集合中查找套接字的访问时间是O(N)。如果我连接了超过几千个客户端,这可能会很长。如果我错了,请纠正我。

嗯,我想我需要一些想法: - )

Groetjes 马库斯

P.S。我为C ++和C标记它,因为它适用于两种语言。

3 个答案:

答案 0 :(得分:4)

截至今天的最佳方法是事件循环,例如libevlibevent

在大多数情况下,您会发现一个线程绰绰有余,但即使不是这样,您也可以始终拥有多个具有单独循环的线程(至少使用libev)。

Libev [ent]为每个操作系统使用最有效的轮询解决方案(任何select或每个插槽的线程更高效。)

答案 1 :(得分:1)

你会遇到几个限制:

  1. fd_set size:这在编译时是可更改的,但默认情况下具有相当低的限制,这会影响select个解决方案。
  2. 每个套接字的线程将在更早的时候耗尽 - 我建议将longs计算放在单独的线程中(如果需要,可以使用池),但是否则单个线程方法可能会扩展。
  3. 要达到500,000,你需要一套机器和我怀疑的循环DNS。

    TCP端口应该不是问题,只要服务器不连接回客户端即可。我似乎总是忘记这一点,不得不提醒。

    我认为文件描述符本身不应该是一个太大的问题,但是将它们放入轮询解决方案可能会更困难 - 当然,您不希望每次都传递它们。

答案 2 :(得分:0)

我认为您可以使用事件模型(epoll +工作线程池)来解决此问题。 首先在主线程中监听和接受,如果客户端连接到服务器,主线程将client_fd分配给一个工作线程,并添加epoll列表,则该工作线程将处理来自客户端的请求。

可以通过问题配置工作线程的数量,并且它必须不再是5000。