如何刷新Python套接字?

13 投票
4 回答
34861 浏览
提问于 2025-04-15 15:34

我写了一个用Python做的服务器,目的是把数据以“标题:消息”的形式发送给客户端。

我希望每条消息都能单独发送,这样客户端就能轻松读取“标题”和“消息”,工作量最小。

可惜的是,我不知道怎么正确地刷新Python的socket,所以当我快速发送多条消息时,这些消息会被一起放在socket的缓冲区里,最后作为一大块发送出去。

举个例子:

服务器发送...

socket.send ("header1:message1")
socket.send ("header2:message2")
socket.send ("header3:message3")

客户端接收到的是... "header1:message1header2:message2header3:message3"

我希望能收到三条单独的消息

header1:message1
header2:message2
header3:message3

我需要一种方法,在每次发送后进行刷新。

4 个回答

1

我之前也遇到过同样的问题,就是想要“清空”一个UDP套接字的缓冲区,这里是我的解决办法:

def empty(sock):
    """Empty the UDP buffer."""
    sock.setblocking(0)
    while True:
        try:
            sock.recv(1024)
        except BlockingIOError:
            sock.setblocking(1)
            return
1

你想做的事情是把数据分成“批次”。

举个例子,当你从文件中读取“行”时,就是在处理“批次”。那么什么是“行”呢?它是以'\n'(换行符)结束的一串字节。再比如,你从文件中读取64KiB的“块”。那么“块”是什么呢?是你自己定义的,因为你每次读取65536个字节。如果你想要一个可变长度的“块”,你只需在“块”前面加上它的大小,然后再读取这个“块”。像“aiff”文件(它的实现也包括MS Windows的.wav和.avi文件)和“mov”文件就是这样组织的。

这三种方法是组织字节流的最基本方式,无论是什么媒介:

  1. 记录分隔符
  2. 固定大小的记录
  3. 带有大小前缀的记录

这些方法可以混合使用或修改。例如,你可以有“可变记录分隔符”,就像XML读取器那样:从第一个'<'开始读取字节,直到第一个'>',在第一个'<'后加一个斜杠,称之为记录结束,然后读取流直到记录结束。这只是一个粗略的描述。

选择一种方法,并在写入和读取时都实现它。如果你还记录下你的选择,那你就定义了你的第一个协议。

24

我猜你是在说通过TCP连接进行通信。

你的方法有点问题。TCP流是由一串字节组成的。你总是需要使用某种分隔符,而不能指望网络本身来帮你分开消息。

如果你真的需要基于数据报的服务,可以考虑使用UDP。在这种情况下,你需要自己处理重传的问题。

为了更清楚:

刷新发送缓冲区通常会产生新的数据包,这正是你所期望的。如果你的客户端读取这些数据包的速度足够快,你可能每次读取到一条消息。

现在想象一下,你通过卫星链接进行通信。由于带宽高且延迟大,最后一个路由器会稍微等待一下,直到缓冲区里有足够的数据,然后一次性发送所有的数据包。这样你的客户端就会毫无延迟地接收到所有的数据包,并且会把所有数据一次性放入接收缓冲区。所以你的分隔就又消失了。

撰写回答