编写一个向客户端推送数据的服务器应用程序(TCP)

4
我正在编写一个客户端-服务器应用程序,其中之一的要求是服务器在从一个客户端接收到更新后,能够将新数据推送给所有其他客户端。这是一个C++(Qt)应用程序,旨在在Linux上运行(客户端和服务器都是),但我更多地寻求如何工作的高层概念思想(尽管低层思想也很好)。

服务器:

它需要(除了其他职责之外)保持一个套接字打开,以便监听来自潜在的n个不同客户端的传入数据包,可能在后台线程上(除了学校里的一些简单例子外,我还没有写过太多关于套接字代码)。在从客户端获取这些数据后,它会处理它并将其输出到所有客户端,对吗?
当然,我不确定它实际上是如何做到这一点的。我猜这意味着它必须与每个客户端保持持久连接(至少是活动客户端),但我甚至在概念上也不明白如何维护此连接(或这些连接的列表)。
那么,我该如何解决这个问题?

最好将TCP连接视为数据流,而不是数据包 - Sam Miller
2个回答

4
通常情况下,当你有多个客户端时,有几种处理方式。
首先,在TCP中,当客户端连接到你时,它们会被放置在一个队列中,直到可以为其提供服务。这是一个给定的,你不需要做任何事情,除了调用 accept 系统调用来接收新的客户端。一旦接收到客户端,你将获得一个套接字,用于读写。谁先读 / 写完全取决于你的协议,但双方都需要知道协议(由你定义)。
一旦你拥有套接字,你可以做一些事情。在简单的情况下,你只需读取一些数据,处理它,写回套接字,关闭套接字并服务下一个客户端。不幸的是,这意味着你一次只能为一个客户端提供服务,因此无法进行“推送”更新。另一种策略是保持所有打开套接字的列表。任何“更新”只需迭代整个列表并写入每个套接字即可。然而,这可能会出现问题,因为它仅允许推送更新(如果客户端发送了请求,那么谁会观察它?)
更高级的方法是为每个套接字分配一个线程。在这种情况下,每次创建套接字时,你会启动一个新线程,其唯一的目的是为一个客户端提供服务。这可以减少延迟并利用多个核心(如果可用),但编写难度较大。此外,如果有10,000个客户端连接,则需要10,000个线程,这太多了。在此情况下,向单个客户端推送更新非常简单(线程只需写入其各自的套接字)。同时向所有客户端推送更新则稍微棘手一些(需要线程事件或生产者 / 消费者队列,两者都不太好实现)
当然,还有无数其他处理方式(每个客户端一个进程、线程池、负载均衡代理等等)。可以说在一个答案中无法涵盖所有这些。我希望这回答了你的基本问题,请让我知道是否需要澄清任何内容。这是一个非常庞大的主题。不过,如果我可以提个建议,处理多个客户端是一个被反复发明的轮子。有非常好的库可用,比原始套接字 IO 更高效和程序员友好。我建议使用 libevent,它将网络请求转换为事件驱动范例(更像 GUI 编程),并且非常高效。

1
Boost.Asio是另一个非常优秀且易于使用的套接字库。 - Sam Miller
好的建议,如果原帖作者已经熟悉Boost,那可能是一个更容易的选择。 - Chris Eberle
@Chris 所以基本上我需要为每个客户端维护一个“保持连接”套接字以推送新数据,并且还需要一种方式(第二个套接字/端口)来监听来自客户端的传入连接? - jbrennan
这不是一个“保持连接”套接字,而是一个套接字。它是与客户端直接通信的渠道。是的,传入队列也恰好是一个套接字。但请放心,在最简单的情况下,您仍然至少需要两个套接字。 - Chris Eberle

1
据我所知,我认为您需要保持一个无限循环(至少直到程序终止),以回答客户端的连接请求。最好将它们添加到某种数组中。使用事件来查看何时向该数组添加了新客户端,并等待其中一个客户端提供数据。然后,您可以对该数据进行必要的操作并将其返回。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接