我正在尝试使用 python 中的套接字将图像从服务器发送到客户端。但是当客户端收到图像时,我尝试使用 Image() 和 Byteio() 显示它,但显示错误:
我试图找出这个错误是从哪里来的,所以我尝试显示客户端接收到的图像的位大小,并将其与服务器端的图像的位大小进行比较,然后我意识到有一个不同之处。服务器端的位大小大于客户端的位大小。也许这就是问题所在。如果是这样,你如何处理这个问题?或者如何使用 Python 中的套接字通过客户端/服务器架构传输图像?
我的服务器代码:
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()
这是我的客户端代码:
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()
这是一个最小的示例,服务器在客户端连接上发送一张图像,客户端接收该图像。正如评论中提到的,OP 代码具有不相关的代码来处理可能的 JSON 响应,该响应超出了问题的范围,并且干扰了图像的接收。
请注意,
recv(n)
在断开连接时接收 1-n 个字节或 0。您负责缓冲数据,直到收到完整的消息。在这种情况下,请确保您准确读取了四个字节的长度,然后准确读取了数据的“length”字节。使用 socket.makefile
可以通过将套接字包装在类似文件的对象中来帮助缓冲,其中 .read(n)
可精确读取 n 个字节,除非遇到错误或 EOF(套接字关闭)。
服务器:
import socket
with socket.socket() as sock:
sock.bind(('', 50000))
sock.listen()
while True:
client, addr = sock.accept()
print(f'{addr}: connected')
with open('downloads/crawdad.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')
客户:
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 header:
length = int.from_bytes(header, byteorder='big')
image = infile.read(length)
image = Image.open(io.BytesIO(image))
image.show()