简体   繁体   中英

Sending an image from client to server via sockets

I made a TCP server and client and when the server asks for a command and receives "screenshot" the client will get that data and send over an image as an byte object, however when I try todo .frombytes() and download it and display it it gives me an error which is "not enough image data".

i've tried increasing the buffer to download it.

Server

import socket
from PIL import Image


class Server:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.clients = []

    def start(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind((self.host, self.port))

        # backlog == how many connections we can have
        server.listen(1)

        while True:
            client, addr = server.accept()

            # Send our command to the client
            message = input("What is your command? ")
            client.send(message.encode(encoding="utf-8"))

            # Receive our data and check what to do with it.
            succesful_screenshot = client.recv(4096).decode(encoding="utf-8")
            if succesful_screenshot == "returnedScreenshot":
                client.settimeout(5.0)
                screenshot = client.recv(4096)

                img = Image.frombytes(data=screenshot, size=(500, 500), mode="RGB")
                img.show()
                print("hit this")


if __name__ == '__main__':
    Server(host='localhost', port=10000).start()

Client

import socket
from PIL import ImageGrab


class Client:
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def start(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.connect((self.host, self.port))

        while True:
            data = server.recv(4096)
            decoded_data = data.decode(encoding="utf-8")
            if decoded_data == "screenshot":
                # If we receive a string from the server which equals "screenshot" then we grab a screenshot
                # We turn that screenshot into a byte object which we send back to the server and then we decrypt there.
                img = ImageGrab.grab()

                bytes_img = img.tobytes()

                # Send that we have taken a screenshot
                server.send("returnedScreenshot".encode("utf-8"))

                # Send the screenshot over.
                server.send(bytes_img)


if __name__ == '__main__':
    Client(host='localhost', port=10000).start()

Error

Traceback (most recent call last):
  File "C:/Users/Kaihan/PycharmProjects/Networking/demo/server.py", line 38, in <module>
    Server(host='localhost', port=10000).start()
  File "C:/Users/Kaihan/PycharmProjects/Networking/demo/server.py", line 32, in start
    img = Image.frombytes(data=screenshot, size=(500, 500), mode="RGB")
  File "C:\Users\Kaihan\AppData\Local\Programs\Python\Python36\lib\site-packages\PIL\Image.py", line 2412, in frombytes
    im.frombytes(data, decoder_name, args)
  File "C:\Users\Kaihan\AppData\Local\Programs\Python\Python36\lib\site-packages\PIL\Image.py", line 815, in frombytes
    raise ValueError("not enough image data")
ValueError: not enough image data

In Server.start you do: screenshot = client.recv(4096) . But you can't be sure that:

  • This will actually read exactly 4096 bytes
  • The client sent exactly 4096 bytes or less

And that's exactly what PIL is telling you: "not enough image data", which means that you didn't read enough data.

You should make sure you read everything the client sent. Try replacing screenshot = client.recv(4096) with the following:

screenshot = b""
chunk = client.recv(4096)
while chunk:
    screenshot += chunk
    chunk = client.recv(4096)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM