C 多线程服务器设计

C 多线程服务器设计,c,multithreading,network-programming,tcpserver,C,Multithreading,Network Programming,Tcpserver,我正在尝试实现一个TCP服务器,它是一个更大项目的一部分。基本上,服务器应该能够与任意数量的客户端(至少32个)保持TCP连接,并为任何请求服务的客户端提供服务。在我们的场景中,假设一旦客户机连接到服务器,它将永远不会关闭连接,除非发生某种故障(例如运行客户机的机器发生故障),并且它将重复从服务器请求服务。所有其他客户端的情况也是如此,即每个客户端都将与服务器保持连接并执行事务。因此,总而言之,服务器将同时维护与客户端的连接,同时根据需要为每个客户端提供服务,并且还应能够接受希望连接到服务器的任

我正在尝试实现一个TCP服务器,它是一个更大项目的一部分。基本上,服务器应该能够与任意数量的客户端(至少32个)保持TCP连接,并为任何请求服务的客户端提供服务。在我们的场景中,假设一旦客户机连接到服务器,它将永远不会关闭连接,除非发生某种故障(例如运行客户机的机器发生故障),并且它将重复从服务器请求服务。所有其他客户端的情况也是如此,即每个客户端都将与服务器保持连接并执行事务。因此,总而言之,服务器将同时维护与客户端的连接,同时根据需要为每个客户端提供服务,并且还应能够接受希望连接到服务器的任何其他客户端连接

现在,我使用berkely socket API的
select()
系统调用实现了上述功能,当我们有少量客户机(比如10台)时,它可以正常工作。但是服务器需要扩展到尽可能高的级别,因为我们正在16核机器上实现它。为此,我研究了各种多线程设计技术,例如每个客户端一个线程等,我认为最好的是线程池设计。现在,在我即将实施时,我遇到了一些问题: 如果我指定主线程接受任意数量的传入连接,并将每个连接文件描述符保存在一个数据结构中,并且我有一个线程池,那么我如何让线程轮询某个特定客户机是否正在请求服务。对于客户端与服务器联系,并在获得服务后关闭连接的场景,该设计非常简单,这样我们就可以从池中选择一个线程,为客户端提供服务,然后将其推回到池中,以便将来处理连接。但是,当我们必须为一组维护连接并间歇性请求服务的客户机提供服务时,最好的方法是什么。所有的帮助都将非常感谢,因为我真的陷入了困境。
谢谢。

使用pthreads,每个CPU一个线程加上一个额外线程

额外线程(主线程)使用listen()系统调用侦听新连接,使用accept()接受新连接,然后确定当前哪个工作线程的连接数最少,为该工作线程的“挂起连接”FIFO队列获取锁/互斥锁,将接受连接的描述符放入工作线程的“挂起连接”FIFO队列,并向工作线程发送“检查队列”通知(例如,使用管道)

工作线程使用“select()”,并向它们接受的任何连接发送/接收数据。如果/当工作线程收到来自主线程的“检查队列”通知时,它将获取其“挂起连接”FIFO队列的锁/互斥锁,并将任何新接受的连接添加到其“fd_set”列表中


用于1024个连接和16个CPU;最终可能会有一个主线程等待新连接(但几乎什么也不做,因为你不会期望有很多新连接),16个工作线程平均每个线程处理64个连接。

每个客户端一个线程几乎肯定是最好的设计。确保在
accept
中始终有至少一个线程被阻塞,等待新连接-这意味着在accept成功后,如果它是最后一个线程,您可能需要在继续之前创建一个新线程。我发现信号量是跟踪产生新监听线程需求的一个很好的原语。

粘贴您的代码,让我们阅读一下。Apache有什么问题?我必须使用SOCKET API用与系统无关的C语言开发服务器。这种传递连接的方法过于复杂,与让空闲线程直接调用
accept
没有任何好处。@R:我宁愿让线程阻塞等待“select()”而不是线程不断地浪费CPU时间轮询“accept()”和“select()”,或者线程由于等待“select()”超时而需要很长时间才能响应“accept()”。被阻止等待“select()”的线程可以从主线程接收通过发送的连接请求。一根管子;这意味着你的工作线程永远不会解锁,除非他们有真正的工作要做(没有轮询)。“我肯定会试试,这是有道理的。”布伦丹说。我在实现时遇到了一个问题,我们如何知道在调用listen()sys调用的主线程中有一些连接挂起,我的意思是listen()指定内核为尝试连接的客户机维护一个队列,我们如何知道当队列有东西时,我们分配了一个工作线程来调用accept()呢. 都很有帮助appreciated@Abdullah:事后看来,在主线程中“accept()”可能更容易,主线程在接受新连接后会将其告知工作线程。您可能还希望每个线程都有一个最近接受的连接队列,其中主线程告诉工作者“检查最近接受的连接队列”(工作者队列上有一个互斥)。将编辑我的答案!“每个客户端一个线程”的问题是,在高负载下,所有这些线程都会争夺有限数量的CPU,这会增加延迟。如果您需要响应1000个接收到的数据包,那么处理500个数据包而不启动500个数据包比处理1000个“半处理”数据包要好(如果考虑到线程切换、线程争锁和其他可伸缩性问题的成本,情况会更糟)。线程之间上下文切换的成本低于大多数系统调用(我已经测量过了;请参阅我的一个问题)。