I'm trying to send an image from a server to a client using sockets in python. But when the client receives the image, I try to display it using Image() and Byteio(), but an error is displayed:
I tried to find out where this error was coming from, so I tried displaying the bit size of the image received on the client side and comparing it with the bit size of the image on the server side, and I realised that there was a difference. The bit size on the server side is greater than that on the client side. Maybe that's where the problem lies. If so, how do you deal with this problem? Or how do you transfer images through a client/server architecture in Python with sockets?
My server code:
import socket
import mysql.connector
from mysql.connector import errorcode
import json
from datetime import datetime
from io import BytesIO
from PIL import Image
host = 'localhost'
port = 50000
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind((host, port))
mySocket.listen()
while 1:
connexion, adresse = mySocket.accept()
with open('WhatsApp Image 2023-10-16 at 17.49.56.jpeg', 'rb') as fichier_image:
image = fichier_image.read()
if type(image)==bytes:
try:
taile_image = len(image)
print(taile_image)
print(taile_image.to_bytes(4, byteorder='big'))
connexion.sendall(taile_image.to_bytes(4, byteorder='big'))
connexion.sendall(image)
except:
pass
else:
try:
resultat_str = json.dumps(resultat, default=str)
connexion.send(resultat_str.encode('utf8'))
except:
pass
connexion.close()
ch = input("<R>ecommencer <T>erminer ? ")
if ch.upper() == "T":
break
mySocket.close()
and this is my client code:
import socket, threading
import json
from io import BytesIO
from PIL import Image
host = 'localhost'
port = 50000
class ThreadEmission(threading.Thread):
def __init__(self, conn):
threading.Thread.__init__(self)
self.connexion = conn
def run(self):
ident = 2
pays='Guinée'
msgClient = "SELECT logo FROM entreprise WHERE identreprise=%s"%ident
self.connexion.send(msgClient.encode('utf8'))
class ThreadReception(threading.Thread):
def __init__(self, conn):
threading.Thread.__init__(self)
self.connexion = conn
self.resultat = None
def run(self):
#print(msgServeur)
try:
msgServeur = self.connexion.recv(1024).decode('utf8')
self.resultat = json.loads(msgServeur)
except :
taille_image_bytes = self.connexion.recv(4)
print('taille_image_bytes ',taille_image_bytes)
taille_image = int.from_bytes(taille_image_bytes, byteorder='big')
print('taille_image', taille_image)
self.resultat= self.connexion.recv(taille_image)
print(len(self.resultat))
#print (type(msgServeur))
self.connexion.close()
def get_resultat(self):
return self.resultat
myClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
myClient.connect((host, port))
th_E = ThreadEmission(myClient)
th_R = ThreadReception(myClient)
#th_E.start()
th_R.start()
#th_E.join()
th_R.join()
resultat = th_R.get_resultat()
print(resultat)
print(type(resultat))
image = Image.open(BytesIO(resultat))
image.show()
Here is a minimal example with the server sending one image on client connection and the client receiving the image. As mentioned in the comments, the OP code had unrelated code to handle a possible JSON response that is outside the scope of the question and was interfering with reception of the image.
Note that recv(n)
receives 1-n bytes or 0 on disconnect. You are responsible for buffering data until you receive a complete message. In this case make sure you read exactly four bytes for the length, then exactly "length" bytes for the data. Using socket.makefile
can help with buffering by wrapping the socket in a file-like object where .read(n)
is available to read exactly n bytes unless an error or EOF (socket close) is encountered.
Server:
import socket
with socket.socket() as sock:
sock.bind(('', 50000))
sock.listen()
while True:
client, addr = sock.accept()
print(f'{addr}: connected')
with open('some_image.jpg', 'rb') as file:
image = file.read()
with client:
length = len(image)
client.sendall(length.to_bytes(4, byteorder='big'))
client.sendall(image)
print(f'{addr}: disconnected')
Client:
import socket
import threading
import io
from PIL import Image
with socket.socket() as sock:
sock.connect(('localhost', 50000))
with sock.makefile('rb') as infile:
header = infile.read(4)
if len(header) == 4:
length = int.from_bytes(header, byteorder='big')
image = infile.read(length)
if len(image) == length:
image = Image.open(io.BytesIO(image))
image.show()
else:
print('incomplete image')
else:
print('incomplete header')