python - 通过套接字发送图像时遇到问题

标签 python sockets stream buffer screenshot

我是 python 新手,我正在尝试制作一个脚本来发送/流式传输我的笔记本电脑槽 socket 的屏幕截图。如果我运行这两个脚本,它可以工作,但几秒钟后(我认为这就是发生的情况:客户端信息重载),它给了我“pickle 数据被截断”错误。我一直在关注的教程仅用于发送字符串消息和使用缓冲区,但问题是我使用的是 numpy腌制的数组,如果我缓冲它,它会将第二个图像写入第一个图像并给出另一个腌制数据截断错误,我不知道该怎么做。

任何帮助表示赞赏。

服务器:

import numpy as np
import socket
import pickle
import time
import mss
import cv2
import sys

s = socket.socket()
shost = socket.gethostname()
host = socket.gethostbyname(shost) 
port = 8080
s.bind((host,port))
s.listen(5)
print(host)
print("Waiting for any incoming connections ... ")
conn, addr = s.accept()
print(addr, "Has connected to the server")

with mss.mss() as sct: #if i want it to be a different size
    monitor = {"top": 0, "left": 0, "width": 1720, "height": 720}


while True:
    img =  np.array(sct.grab(sct.monitors[1]))
    pack = pickle.dumps(img)
    conn.send(pack)
    print(sys.getsizeof(pack))

客户:
import socket
import numpy as np
import cv2
import pickle
import time


s = socket.socket()
host = input(str("Please enter the host address of the sender : "))
port = 8080
s.connect((host,port))
print("Connected ... ")

while True:
    pack = s.recv(4196540)        
    frame = pickle.loads(pack)
    cv2.imshow("Screen", frame)
    pack = ' '
    if cv2.waitKey(1) == 27:
        break

cv2.destroyAllWindows()

最佳答案

socket.recv() 虽然看起来相似但行为方式与 .read() 不同如果像对象这样的文件。 “原始”套接字编程也不会为您做很多家务,这取决于您的代码来处理它。

流套接字( SOCK_STREAM 类型,它是默认使用 socket.socket() 打开的类型,就是一个字节流,它基本上与您通过它的内容无关。使事情变得更复杂,如前所述Michael Butscher 在评论中(这与 read() 的相似性可能令人困惑),它的第一个参数 bufsize 并没有说明您将收到多少数据,它只限制了您准备一次接收的最大数量。它基本上说,我有这个大小的缓冲区,给我你能达到的那个大小。

如果你知道在你的情况下你要为任何给定图像接收多少数据(因为它们固定大小的屏幕截图我猜你可能很幸运),你需要不断重复 recv()调用直到您获得完整的图像,然后对其执行操作并继续进行下一个。

这意味着您可以替换:

pack = s.recv(4196540)

有类似的东西:
item_size = 4196540
pack = b''
while len(pack) < item_size:
    remains = item_size - len(pack)
    bufsize = 4096 if remains > 4096 else remains
    pack += s.recv(bufsize)

有更多的方法来处理它,但这基本上是运行 recv直到 pack包含 4196540字节的数据(大概是一个腌制的图像),然后您可以继续处理它。

否则,您将不得不采用其他技术:例如,您可以定义自己的协议(protocol),其中首先 n bytes 是后面的文件的大小,然后您知道下一个项目需要多少数据。或者为每个项目打开新连接( recv() 在另一侧已关闭的套接字上不会阻塞并产生 b'' )。

顺便说一句,最后一条评论也意味着,在发送最后一张图片后,服务器可以执行 conn.close()并退出(或监听新的传入连接),我们可以在上面的代码段中再做一个更改,即代替:
pack += s.recv(bufsize)

说:
buf = s.recv(bufsize)
if not buf:
    s.close()
    break  # end the "while True" loop
pack += buf

也停止在客户端接收。

还有一个关于你提到的教程的注释。在琐碎的情况下......例如发送短字符串消息,虽然你不应该依赖它,但你经常会幸运和recv所有您期望的数据都集中在一个 block 中。

关于python - 通过套接字发送图像时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60587912/

相关文章:

java - 为什么不创建单独的线程?

c# - WCF错误: The socket connection was aborted

python - 如何优雅地解决Python KeyError(Python csv库)

java - 使用 java 套接字连接到 URL

python - Django ImportError 在/无论我做什么

android - 如何从直接视频链接将视频流式传输到 VLC(适用于 Android 或 iPhone)

flutter - StreamBuilder 和 Flutter 中的流问题(接收重复数据)

php - php 流输出上的删除线字符

python - 从 Matplotlib 图例中排除 Cartopy 元素

Python 标签图像不存在,但 os.path 说它存在