我是 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/