如果发送太快,Python 套接字 recv() 不会收到每条消息

mic*_*616 2 python sockets

我通过套接字将鼠标坐标从 python 服务器发送到 python 客户端。每次在服务器上捕获鼠标移动事件时都会发送鼠标坐标,这意味着经常(每秒十几个)。

问题是当我在不同的主机上使用 python 服务器和 python 客户端时。然后只有部分消息传递给客户端。例如,传递了 3 条第一条消息,未传递 4 条消息,传递了 4 条消息等...

当服务器和客户端在同一主机(本地主机)上时,一切都很好。

当服务器和客户端在不同的主机上时一切都很好,但我使用标准的 Windows Telnet 客户端而不是 python 客户端从服务器读取消息。

我注意到当我在发送的每条消息之间使用 time.sleep(0.4) 中断时,所有消息都会被传递。问题是我需要实时的信息而不是这样的延迟。是否可以使用套接字在 Python 中实现这一点?

下面是我使用的 python 客户端代码:

import pickle
import socket
import sys


host = '192.168.1.222'
port = 8888
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print "Faile. Error:" + str(msg[0]), "Error message : " + msg[1]
    sys.exit()

mySocket = socket.socket()
mySocket.connect((host,port))

while 1:
    data = mySocket.recv(1024)
    if not data: break
    load_data = pickle.loads(data)

    print 'parametr x: ' + str(load_data[0])
    print 'parametr y : ' + str(load_data[1])

mySocket.close()
Run Code Online (Sandbox Code Playgroud)

Ste*_*ich 5

您正在使用 TCP (SOCK_STREAM),这是一种可靠的协议,即使接收方没有足够快地读取数据,它(与 UDP 相反)也不会丢失任何消息。相反,TCP 会降低发送速度。
这意味着问题一定出在您的应用程序代码中。

一种可能性是问题出在您的发件人身上,即您使用socket.send并且不检查您打算发送的所有字节是否真的被发送。但是需要进行此检查,因为socket.send如果操作系统的套接字缓冲区已满,则可能只会发送部分数据,如果客户端读取数据的速度不够快,就会发生这种情况。

另一种可能性是您的socket.recv调用接收到的数据多于您的pickle.loads需要,而其余数据将被丢弃(不确定如果pickle.loads提供的数据过多是否会引发异常)。请注意,TCP 不是消息而是流协议,因此您可能有更多socket.recv将返回包含多个腌制对象的缓冲区,但您只读取第一个。这种情况在网络上发生的可能性高于本地主机,因为默认情况下,TCP 层会尝试将多个send缓冲区连接到单个 TCP 数据包中,以便更好地利用连接(即更少的开销)。并且在同一个recv呼叫中收到这些消息的可能性很高。通过放置一个sleep(0.4)在发送方,您已经有效地关闭了 TCP 的这种优化,有关详细信息,请参阅NAGLE 算法

因此,实现您想要的正确方法是:

  • 确保所有数据都在服务器上传递,即检查 的返回socket.send
  • 确保解压缩收到的所有邮件。为此,您可能需要在 TCP 流之上添加一些消息层,以找出消息边界的位置。