通过 socket.recv() 在 python 中通过 tcp/ip 接收损坏的图像



我正在尝试将图像从树莓派流式传输到我的Windows笔记本电脑(python 3.6.3)并接收损坏的图像(更多详细信息遵循代码)。以下是我的代码。

客户端:

import picamera
import socket
import struct
import time
import io
stream_client= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
stream_client.connect(('192.168.1.106',9000))
print('connected')
camera = picamera.PiCamera()
camera.resolution=(320,240)
camera.color_effects=(128,128)
camera.framerate=18
time.sleep(2)
stream = io.BytesIO()
count=0
start=time.time()
try:
for i in camera.capture_continuous(stream,'jpeg',use_video_port=True):
count+=1
stream_client.sendall(struct.pack('<L',stream.tell()))
stream_client.sendall(struct.pack('<h',count))
stream_client.sendall(stream.getvalue())
stream.seek(0)
stream.truncate()
if(time.time()-start>2):
break
finally:
stream_client.sendall(struct.pack('<L',0))
stream_client.close()
camera.close()
print('connection closed')

保存损坏图像的服务器端代码:

import socket
import struct
import io
import cv2
import numpy as np
server_socket= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(('192.168.1.106',9000))
server_socket.listen(1) 
print('Server is ready')
(client_conn,client_addr)= server_socket.accept()
image_stream= io.BytesIO()
try:
while True:
data_size=struct.unpack('<L',client_conn.recv(4))[0]
counter=struct.unpack('<h',client_conn.recv(2))[0]
print('Image Count = ',counter)
print('Image size = ',data_size)
if not data_size:
break
image_stream.write(client_conn.recv(data_size))
image= np.fromstring(image_stream.getvalue(),dtype=np.uint8)
img=cv2.imdecode(image, -1)
print(image) # just wanted to see how the image data looked 
cv2.imwrite((str(counter)+'.jpeg'),img)
image_stream.seek(0)
image_stream.truncate()

finally:
server_socket.close()
print('Exception Detected ! Server Closed.')

上面的服务器代码保存了大部分损坏的图像和垃圾图像,偶尔保存正确的图像。我尝试增加和减少缓冲区大小,但我认为这没有意义,也没有帮助(事实上它使问题恶化)。
我还使用 makefile() 方法实现了一个服务器代码,我收到的图像是正确的。

我在想的是,这个问题存在,因为我没有缓冲数据并将其直接馈送到流中。我觉得这是正常工作的服务器代码和不正确的服务器代码之间的唯一区别。

我知道客户端中的 sendall() 方法会自动发送丢失(或损坏?)的数据,并且我觉得这种重新传输不会由 recv() 方法自动处理? 这也可能是问题的原因吗?还是这里发生了完全不同的事情?

无论如何,我想通过 recv() 方法实现图像传输代码,因为我相信它会加深我对套接字编程的理解。有人可以告诉我我做错了什么吗?任何帮助,不胜感激。

PS:这是我在Stackoverflow的第一个问题,所以我试图尽可能详细地详细说明我的问题和想法。如果你觉得我应该减少/增加细节,请告诉我。欢呼:)

image_stream.write(client_conn.recv(data_size))

您希望recv返回所有data_size字节。但是,size 参数仅给出它将读取的最大字节数。从文档中:

socket.recv(bufsize[, flags])
...一次接收的最大数据量由 bufsize 指定。

您必须检查返回值实际接收了多少数据,然后再次调用recv,直到您拥有所有数据,即如下所示:

while data_size>0:
buf = client_conn.recv(data_size)
if buf == '':
raise Exception("unexpected eof")
data_size -= len(buf)
image_stream.write(buf)

最新更新