我是python的新手,我正在尝试编写一个脚本来发送/流式传输我的笔记本电脑插槽的屏幕截图。如果我运行这两个脚本,它可以工作,但在几秒钟后(我认为这就是发生的情况:客户端信息过载),它会给我"pickle data was truncated“错误。我一直遵循的教程只是为了发送字符串消息和使用缓冲区,但问题是我使用的numpy数组是pickle的,如果我缓冲它,它会将第二个图像写入第一个图像,并给出另一个pickle数据截断错误,我不知道该怎么办。
任何帮助都是非常感谢的。
服务器:
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()发布于 2020-03-10 05:01:59
如果文件类似于对象,则看起来类似的socket.recv()与.read()的行为方式不同。“原始”套接字编程也不会为您做很多内务工作,它取决于您的代码来处理它。
流套接字(默认情况下使用socket.socket()打开的SOCK_STREAM类型)就是一个字节流,它本质上与您传递的内容无关。让事情变得更复杂的是,正如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字节的数据(假设是一个经过酸洗的图像),然后您就可以继续处理它了。
否则,您将不得不使用其他技术:例如,您可以定义自己的协议,其中第一个n字节是随后的文件大小,然后您就可以知道下一项需要多少数据。或者为每个项目打开新的连接(在另一端已关闭的套接字上的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。
https://stackoverflow.com/questions/60587912
复制相似问题