【问题标题】:python sending numpy arrays over socket with pickle - not workingpython通过带有pickle的套接字发送numpy数组-不起作用
【发布时间】:2021-03-23 10:02:18
【问题描述】:

为了通过套接字发送 numpy 数组(图像),我使用了 pickle,但有时它会显示“_pickle.UnpicklingError:pickle 数据被截断”,我找到了一些修复方法,但它们没有起作用,原因有一个:我正在发送每次可能的数组,因为我正在制作一个屏幕共享脚本,解决方案是放置一个循环,将部分 msg 组合起来。并且由于我在每次运行 while 循环时都发送数组,因此它将所有数组组合在一起。我该怎么办?

服务器:

import cv2
import numpy
import pyautogui
import pickle
import time
import socket
a = pickle.dumps(numpy.array([4556]))
print (a)
b = pickle.loads(a)
print(b)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((socket.gethostname(), 3948))
server.listen()
client, addres = server.accept()
print("listening")
while True:
    screen = pyautogui.screenshot()
    cv2thing = numpy.array(screen)
    rgb = cv2thing[...,::-1].copy()
    client.send(pickle.dumps(rgb))
    print("sent")
    if cv2.waitKey(1) == ord('q'):
        break

客户:

import socket
import cv2
import pickle

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((socket.gethostname(), 3948))
print("connected")
while True:
    cv2.imshow('frame', pickle.loads(client.recv(999999999)))

    if cv2.waitKey(1) == ord('q'):
        cv2.destroyAllWindows()
        break

【问题讨论】:

  • 你没有使用sendall();无法保证 send() 发送所有内容。
  • 通过网络发送未压缩的 RGB 屏幕抓图效率非常低... iMac Pro 的 RGB 全屏抓图为 43MB,因此您将在千兆以太网上每秒获得 2 帧。您可能希望在发送前编码为 PNG 或 JPEG。

标签: python arrays numpy sockets python-sockets


【解决方案1】:

这是 TCP 套接字的常见错误。 TCP 协议是一种 协议。它保证所有发送的字节都将以相同的顺序接收,但不保证数据包级别。这意味着数据包可能会被连接上的任何元素拆分或重组:发送方网络驱动程序、接收方部分或传输中的任何元素(路由器、网关等)。

要可靠地接收完整的消息,您必须准备好重新组装数据包,以防消息被拆分。但这也意味着您必须使用更高级别的协议来标记消息的结束。最简单的一种是在发送消息后关闭(而不是关闭...)套接字,但它只能用于每个连接的单个消息。

但是在这里你可以使用pickle 可以本地使用流协议并且不依赖数据包大小的事实,前提是你有一个类似对象的文件。恕我直言,一种简单的方法是在套接字上构建一个最小的包装器。您可以手动构建一个

class SocketReader(io.RawIOBase):
    def __init__(self, s):
        self.s = s
    def readable(self):
        return True
    def readinto(self, b):
        return self.s.recv_into(b)

但使用 Python 套接字的makefile 方法更简单:

import socket
import cv2
import pickle
import io

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((socket.gethostname(), 3948))
print("connected")
fd = client.makefile()
while True:
    cv2.imshow('frame', pickle.load(fd))

    if cv2.waitKey(1) == ord('q'):
        cv2.destroyAllWindows()
        break

【讨论】:

  • 还有sock.makefile(),不用手动包东西了……
  • @AKX:谢谢!我知道应该存在这样的东西,但我找不到它......
  • 它不起作用,因为 pickle.load() 没有得到这个包装对象,类中的任何方法都可以让我得到字节 msg?
  • @DeepSpace9: 你能解释一下pickle.load() 没有得到这个包装对象 是什么意思吗?它在我自己的测试中发现...
猜你喜欢
  • 2014-12-10
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多