使用套接字发送多个图像
Sending multiple images with socket
在使用 Python 制作 VNC 的雄心勃勃的尝试中,我试图不断将一个用户(服务器)的屏幕截图发送到另一个用户(客户端)。经过几个小时的尝试并达到了鲍尔默的巅峰,我终于做到了。但是,现在我的问题是发送多张图像,它们是连续的。我首先尝试将所有二进制数据写入一个文件,但没有成功。当打开第二张图片时,它崩溃了。我认为这可能是因为二进制数据不知何故被破坏了,所以我尝试为每个图像制作一个新文件,但我遇到了同样的问题。我知道 Tcp 是一个恒定的数据流,因此很难知道第一个图像的结尾和下一个图像的开始,但是通过创建另一个文件,我认为我会很好。
非常感谢任何帮助解决此问题 and/or 提高效率的方法:)
服务器端:
import socket
from PIL import Image, ImageGrab
PORT = 10007
HOST = '127.0.0.1'
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
counter = 3
while counter > 0:
image = ImageGrab.grab(bbox=None)
image.save('test.png')
f = open('test.png', 'rb')
l = f.read(1024)
while (l):
conn.send(l)
l = f.read(1024)
f.close()
print('Done sending curr image')
counter -= 1
conn.close()
客户端:
import socket
from PIL import Image
HOST = '127.0.0.1'
PORT = 10007
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
counter = 1
while counter != 3:
fname = 'image' + str(counter) + '.png'
with open(fname, 'wb') as file:
print('file opened')
while True:
data = s.recv(1024)
if not data:
break
else:
file.write(data)
file.close()
currImg = Image.open(fname)
currImg.show()
counter += 1
s.close()
您的接收者不知道一个文件何时结束而下一个文件何时开始。解决这个问题的最简单方法是在发送每个文件之前将文件的长度(可能是 4 字节无符号值)发送到接收方。然后接收方可以读取长度,读取文件,读取长度,读取文件,...
为了提高效率,您可以停止将文件数据保存到两端的实际文件中,而是将其保存到(显然,从中读取)内存缓冲区中。有关如何执行此操作的说明,请参阅 this answer。在 Python 3 中,您似乎会使用 BytesIO
模块。
另一项改进是只发送自上次发送以来发生变化的屏幕部分的图像数据。为此,您需要弄清楚如何将当前捕获与前一个捕获进行比较。对于第一遍,您可以使用 PIL.ImageChops.difference
,然后使用 PIL.Image.getbbox
,然后仅编码并发送当前捕获的那个区域。为此,发送方不仅要告诉接收方 PNG 的大小,还要告诉接收方在输出屏幕图像中应该绘制新图像补丁的位置。因此,除了大小和编码图像数据之外,您还需要发送一个位置。
在使用 Python 制作 VNC 的雄心勃勃的尝试中,我试图不断将一个用户(服务器)的屏幕截图发送到另一个用户(客户端)。经过几个小时的尝试并达到了鲍尔默的巅峰,我终于做到了。但是,现在我的问题是发送多张图像,它们是连续的。我首先尝试将所有二进制数据写入一个文件,但没有成功。当打开第二张图片时,它崩溃了。我认为这可能是因为二进制数据不知何故被破坏了,所以我尝试为每个图像制作一个新文件,但我遇到了同样的问题。我知道 Tcp 是一个恒定的数据流,因此很难知道第一个图像的结尾和下一个图像的开始,但是通过创建另一个文件,我认为我会很好。
非常感谢任何帮助解决此问题 and/or 提高效率的方法:)
服务器端:
import socket
from PIL import Image, ImageGrab
PORT = 10007
HOST = '127.0.0.1'
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
counter = 3
while counter > 0:
image = ImageGrab.grab(bbox=None)
image.save('test.png')
f = open('test.png', 'rb')
l = f.read(1024)
while (l):
conn.send(l)
l = f.read(1024)
f.close()
print('Done sending curr image')
counter -= 1
conn.close()
客户端:
import socket
from PIL import Image
HOST = '127.0.0.1'
PORT = 10007
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
counter = 1
while counter != 3:
fname = 'image' + str(counter) + '.png'
with open(fname, 'wb') as file:
print('file opened')
while True:
data = s.recv(1024)
if not data:
break
else:
file.write(data)
file.close()
currImg = Image.open(fname)
currImg.show()
counter += 1
s.close()
您的接收者不知道一个文件何时结束而下一个文件何时开始。解决这个问题的最简单方法是在发送每个文件之前将文件的长度(可能是 4 字节无符号值)发送到接收方。然后接收方可以读取长度,读取文件,读取长度,读取文件,...
为了提高效率,您可以停止将文件数据保存到两端的实际文件中,而是将其保存到(显然,从中读取)内存缓冲区中。有关如何执行此操作的说明,请参阅 this answer。在 Python 3 中,您似乎会使用 BytesIO
模块。
另一项改进是只发送自上次发送以来发生变化的屏幕部分的图像数据。为此,您需要弄清楚如何将当前捕获与前一个捕获进行比较。对于第一遍,您可以使用 PIL.ImageChops.difference
,然后使用 PIL.Image.getbbox
,然后仅编码并发送当前捕获的那个区域。为此,发送方不仅要告诉接收方 PNG 的大小,还要告诉接收方在输出屏幕图像中应该绘制新图像补丁的位置。因此,除了大小和编码图像数据之外,您还需要发送一个位置。