通过套接字将图像作为字节

时间:2016-12-10 13:21:31

标签: python python-3.x sockets

我想将服务器的屏幕截图发送到客户端,为此,我想将图像作为字节发送,并将其拆分为部分,每个部分的长度为1024.

首先,程序执行多项操作,它还发送文件,时间等。所以客户端需要告诉服务器他/(它)?想要一个图像,所以他先发送'Img',然后服务器返回'Img',当客户收到'Img'时,他开始收听所有部分,服务器开始发送所有部分,当最后一部分发送后,服务器发送'已发送'。

到目前为止我的代码: Client.py:

def listen_for_image():
    bytes_data = socket_con.recv(1024)
    part = bytes_data
    i = 1
    print("Part #", str(i))
    while part.decode() != 'Sent':
        part = socket_con.recv(1024)
        bytes_data += part
        i += 1
        print("Part #", str(i))
    return bytes_data


    socket_con.send('Img')
    data_back = socket_con.recv(1024)
    if data_back.decode() == 'Img':
        bytes_full_data = listen_for_image()
        img = Image.frombytes('RGB', (1366, 768), bytes_full_data)
        img.save('newimg.jpg')

Server.py:

def send_screen_shot():
    con.send('Img'.encode())
    image = ImageGrab.grab()
    start = 0
    end = 1024
    while end < len(image.tobytes()):
        con.send(image.tobytes()[start:end])
        start = end + 1
        end += 1024
    con.send("Sent".encode())


if con.recv(1024).decode() == 'Img':
        send_screen_shot()

请注意,我的程序更多,所以这不是完整的代码,只是需要的部分,如果你需要别的东西,请问:)

我的代码的问题是在客户端我收到错误:

Traceback (most recent call last):
  File "C:/Users/dodob/PycharmProjects/untitled/client.py", line 33, in <module>
    bytes_full_data = listen_for_image()
  File "C:/Users/dodob/PycharmProjects/untitled/client.py", line 14, in listen_for_image
    while part.decode() != 'Sent':
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

修改 我尝试切换编码器以解决此问题,例如:

Client.py:

def listen_for_image():
    bytes_data = socket_con.recv(1024)
    part = bytes_data
    i = 1
    print("Part #", str(i))
    while part.decode('ISO-8859-1') != 'Sent':
        part = socket_con.recv(1024)
        bytes_data += part
        i += 1
        print("Part #", str(i))
    return bytes_data

Server.py:

def send_screen_shot():
    con.send('Img'.encode())
    image = ImageGrab.grab()
    start = 0
    end = 1024
    while end < len(image.tobytes()):
        con.send(image.tobytes(encoder_name='ISO-8859-1')[start:end])
        start = end + 1
        end += 1024
    con.send("Sent".encode('ISO-8859-1'))

但是我在服务器端遇到错误:

Traceback (most recent call last):
  File "C:\Python\Python35\lib\site-packages\PIL\Image.py", line 437, in _getencoder
    encoder = getattr(core, encoder_name + "_encoder")
AttributeError: module 'PIL._imaging' has no attribute 'ISO-8859-2_encoder'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/dodob/PycharmProjects/untitled/server.py", line 42, in <module>
    send_screen_shot()
  File "C:/Users/dodob/PycharmProjects/untitled/server.py", line 19, in send_screen_shot
    con.send(image.tobytes(encoder_name='ISO-8859-2')[start:end])
  File "C:\Python\Python35\lib\site-packages\PIL\Image.py", line 681, in tobytes
    e = _getencoder(self.mode, encoder_name, args)
  File "C:\Python\Python35\lib\site-packages\PIL\Image.py", line 441, in _getencoder
    raise IOError("encoder %s not available" % encoder_name)
OSError: encoder ISO-8859-2 not available

客户端一直这样运行:

...
Part # 2376824
Part # 2376825
Part # 2376826
Part # 2376827
Part # 2376828
Part # 2376829
Part # 2376830
Part # 2376831
Part # 2376832
Part # 2376833
Part # 2376834
...

我认为这个错误是因为没有这样的编码器但是我尝试了多个编码器而且每次都会发生..但无论如何,我不知道为什么客户端一直在运行,recv函数应该停止直到它收到一些东西,并且它在这里永远运行。

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

只需使用

while part != b'Sent':

和整个风格相同。您的问题是您正在尝试解码图像中的二进制数据,文本。不是。而且您不需要将其转换为文本以与已知值进行比较 - 您只需使用 bytes 作为已知值。

你想改变这个:

while end < len(image.tobytes()):
    con.send(image.tobytes(encoder_name='ISO-8859-1')[start:end])
    start = end + 1
    end += 1024
con.send("Sent".encode('ISO-8859-1'))

对此:

img_bytes = image.tobytes()
while end < len(img_bytes):
    con.send(img_bytes[start:end])
    start = end + 1
    end += 1024
con.send("Sent".encode())

这样可以节省每次将图像重新转换为字节的麻烦。如果您的图片大小为1024000字节,则称该功能 2,000 次。不要那样做。这可能不是一个严重的问题,因为网络传输速度要慢几个数量级,但是根据图像的大小,你仍然可以在十分之一到几秒的时间内剃掉任何东西。

哦,还有一件事:

while part and part != b'Sent':
    part = socket_con.recv(1024)
    bytes_data += part
    i += 1
    print("Part #", str(i))

这样,如果套接字关闭,你实际上会退出循环。当套接字关闭时,保证.recv将返回一个空字符串(字节)。这评估为False,因此如果您收到 no data ,那么它将退出此循环。

答案 1 :(得分:0)

如果您像这样通过套接字发送图像,您会注意到还有一些字节尚未发送。
为了避免这种情况,请替换

start = end + 1

start = end