【问题标题】:Best way to send periodic message to client using sockets使用套接字向客户端发送定期消息的最佳方式
【发布时间】:2013-02-23 23:43:50
【问题描述】:

有一个应用程序需要向一堆客户端发送消息。客户端是用户计算机上的应用程序,这些应用程序有时一次运行数天。服务器要么有新的指令,要么没有。有时两条新指令之间有 10 分钟的间隔,有时是一小时,有时是一天。消息是固定长度的。

实现这一点的最佳方法是什么?我应该让客户端每 10 秒轮询一次服务器吗?每次新客户端连接时我是否应该在服务器上创建一个新线程,并保持连接直到有新指令,然后将其发送给客户端并让客户端创建一个新连接?

或者我应该将消息推送给客户端吗?我正在考虑如何做到这一点,我想出了这个: 服务器服务器既是服务器又是客户端。当客户端握手时,它会将其地址提供给服务器。然后服务器开始充当客户端(显然,还充当服务器以使其他客户端能够连接),并与客户端保持连接。客户端就像服务器一样,等待消息。

最后一个似乎相当复杂。做这个的最好方式是什么?来自服务器的新消息(“指令”)应该在服务器“拥有”它们之后至少 15 秒到达客户端。

顺便说一句,服务器应用程序将在 Windows 上运行。我不确定的客户,但让我们假设多平台。服务器和客户端应用程序都是用 Python 编写的。

感谢您的宝贵时间。

【问题讨论】:

  • 或许xmpp协议能给你一些思路? (en.wikipedia.org/wiki/XMPP)
  • @thebjorn XMPP 对于我正在做的事情似乎有点矫枉过正,我想。但我过去曾用它来通过互联网进行交流。

标签: sockets


【解决方案1】:

我会让每个客户端打开到服务器的连接,然后等待读取任何数据。只要有消息要发布,服务器就会写入所有连接的客户端。

具体来说,服务器应该socket()bind()listen(),然后进入accept()循环。对于每一个接受的新客户端,它应该只将连接的套接字添加到活动客户端列表中,而不是读取或写入任何内容(除非可能是初始应用程序级握手或身份验证,如果适用的话;在这种情况下,它应该在单独的线程、分叉进程或非阻塞事件循环中执行握手或身份验证,以避免缓慢的客户端锁定其他正在进行的身份验证甚至接受循环。)

客户端应连接到服务器(并在适用的情况下执行握手或身份验证),然后等待它为他们提供任何数据。客户端等待套接字的方式传统上是使用poll()select() 完成的。这些调用可以在单独的线程或进程中以阻塞方式完成;或以非阻塞方式,在主应用程序循环中或由循环计时器触发。

只要服务器有消息要发布,它就会遍历连接的客户端列表,对每个连接的客户端执行write() 消息。

客户端随后将从其当前或下一个poll()select() 返回,并指示套接字具有可读数据,并且它们将继续处理read() 消息。

【讨论】:

  • 感谢您的帮助。但是为什么不使用send()recv()recv() 也是一个阻塞调用,消息的大小是固定的。使用read()write() 代替recv()write() 有什么优势吗?
  • send()recv() 用于通过 UDP 进行通信,这是一种无连接协议,无法保证交付。 UDP 数据包可能无序到达、多次到达或根本没有到达。在您的情况下,我假设您希望客户端知道它是否仍然连接到服务器,以便它收到任何可用的消息。这就是 TCP 连接、read()write() 的用途。
  • 谢谢!我不知道。我已经阅读了一些关于套接字的内容,但我没有阅读过。 Python Sockets HOWTO 没有提及任何相关内容(docs.python.org/2/howto/sockets.html)。你说的正是我想要的(“客户端知道它是否仍然连接到服务器,以便它会在它们可用时立即接收任何消息”)
  • 还有一个问题:如何删除与列表断开连接的客户端?我应该只添加一个try 语句,并删除尝试写入它们时抛出异常的套接字吗?看起来不是很优雅,因为在迭代列表时无法从列表中删除项目。
  • try 并删除听起来不错。在您的情况下,您不需要保留项目的顺序,但您确实需要直接处理每个项目以将其删除。所以你最好使用set() 的客户端套接字。要从正在迭代的集合(或列表或字典)中删除项目,您可以只迭代一个副本:for x in set(a_set): ... a_set.remove(x) 添加的set() 构造函数将制作集合的副本,允许您进行迭代和修改它。
猜你喜欢
  • 1970-01-01
  • 2018-05-16
  • 2023-04-01
  • 2019-08-25
  • 2017-08-14
  • 2017-07-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多