该程序是在 Linux 上用 C 语言开发的客户端服务器套接字应用程序。有一个远程服务器,每个客户端都连接到该服务器并将自己记录为在线。在任何给定时间点,很可能会有多个客户端在线,所有客户端都试图连接到服务器以将自己记录为在线/忙碌/空闲等。那么服务器如何处理这些并发请求。什么是好的设计方法(每个连接请求的分叉/多线程可能?)?
5 回答
我个人会对服务器使用事件驱动的方法。在那里你注册一个回调,一旦连接到达就会被调用。以及每当套接字准备好读取或写入时的事件回调。
与线程相比,拥有大量连接,您将获得巨大的性能和资源优势。但我也更喜欢这个,因为它的连接数较少。
如果您确实需要使用多个内核,或者如果您有一些请求可能需要更长的时间来处理并且在没有线程的情况下处理它太复杂,我只会使用线程。
我使用libev作为基础库来处理事件驱动的网络。
一般来说,您需要一个线程池来服务请求。
一个典型的结构将从一个线程开始,该线程除了将传入请求排队之外什么都不做。由于它做的不多,一个线程通常很容易跟上网络的最大速度。
这会将项目放入某种并发队列中。然后你有一个其他线程池从队列中读取项目,做需要的事情,然后将结果存放在另一个队列中(并重复,直到服务器关闭)。
最后,您有另一个单线程,它只从结果队列中获取项目,并将回复发送给客户端。
看看 Comer 的“Internetworking with TCP/IP”第 3 卷(BSD 套接字版本),它有详细的示例,用于编写服务器和客户端的不同方式。完整的代码(不幸的是没有解释)在网上。或者在http://tldp.org中翻找,您会找到一系列教程。
最好的方法是结合事件驱动模型和多线程模型。
您创建了一堆非阻塞套接字,但线程数应该少得多。即每个线程 10 个套接字。
然后,您只需以非阻塞模式在每个线程上侦听一个事件(传入请求)并在它发生时对其进行处理。
这种技术通常比单独的非阻塞套接字或多线程模型执行得更好。
select 或 poll 或 epoll
这些是 *nix 系统上的工具,用于将多个事件源(连接)聚合到单个等待点。服务器将连接添加到数据结构中,然后通过调用 select 等来等待。当这些连接中的任何一个发生问题时,它会被唤醒,找出哪个连接,处理它,然后重新进入睡眠状态。详见手册。
在这些机制之上构建了几个更高级别的库,这使得它们的编程更加容易,例如 libevent、libev 等。