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

时间:2016-10-08 11:04:43

标签: python sockets

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

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

当服务器和客户端位于同一主机(localhost)上时,一切都很好。

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

我注意到当我在发送的每条消息之间使用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()

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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