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

Receiving corrupt Images over tcp/ip in python via socket.recv()

我正在尝试将图像从 raspberry pi 流式传输到我的 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()方法实现图像传输代码,因为我相信它会加深我对套接字编程的理解。有人可以告诉我我做错了什么吗?感谢任何帮助。

P.S:这是我在 Whosebug 上的第一个问题,所以我尽可能详细地描述了我的问题和想法。如果您觉得我应该 reduce/increase 详细说明,请告诉我。干杯 :)

    image_stream.write(client_conn.recv(data_size))

您期望 recv 到 return 所有 data_size 字节。但是,大小参数只给出了它将读取的最大字节数。来自 the documentation:

socket.recv(bufsize[, flags])
... The maximum amount of data to be received at once is specified by bufsize.

您必须检查 return 值实际收到了多少数据,然后再次调用 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)