Search code examples
pythonpython-3.xsocketsopencvtcp

Cv2:problem recieving full data from socket


i am trying to send frames over socket and after encoding they are usualy 50 000 - 80 000 bytes so i am reciving data by loop but since client is sending frames always the loop in the code bellow wont break so when i run nothing happens and the reciving loop keep going

Client

import socket
import cv2
import time
s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
s.connect(("127.0.0.1",60124))
camera = cv2.VideoCapture(0)
while True :
    r , f = camera.read()
    f = cv2.imencode(".jpg",f)[1].tostring()
    s.sendall(f)

Server

import socket
import numpy as np
import cv2
s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
s.bind(("127.0.0.1",60124))
s.listen(5)
c , a = s.accept()

while True :
    data = ""
    while True:
        f = c.recv(1024)
        if not f :
            break
        data += f
    x = np.fromstring(data , np.uint8)
    var = cv2.imdecode(x , cv2.IMREAD_COLOR)
    cv2.imshow("Camera" , var)
    cv2.waitKey(1)

Helpp plss


Solution

  • I suggest you to send the length first, and then the data.
    When the server receive the "payload" length, it knows how many data bytes expect.

    The client:

    • send len(f) as 8 bytes
    • send data f

    The server:

    • receive 8 bytes to get len_f.
    • receive len_f of data bytes.
      There is no need to receive the data as chunks of 1024 bytes.

    In my example, len_f is encoded as base64 format.
    The number of bytes for sending len_f is always 8 bytes (due to base64 automatic padding).

    You may encode the data as base64 as well.
    It's important if you are sending the data through HTTP.
    I put the base64 encoding/decoding of the image data in comment.
    Only the length is encoded as base64 (you may alternatively send the length as text format).


    Client:

    import socket
    import numpy as np
    import cv2
    import base64
    
    s = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 60124))
    
    width, height, n_frames = 640, 480, 100  # 100 frames, resolution 640x480
    
    for i in range(n_frames):
        # Generate synthetic image:
        img = np.full((height, width, 3), 60, np.uint8)
        cv2.putText(img, str(i+1), (width//2-100*len(str(i+1)), height//2+100), cv2.FONT_HERSHEY_DUPLEX, 10, (30, 255, 30), 20)  # Green number
    
        # JPEG Encode img into f
        _, f = cv2.imencode('.JPEG', img)
    
        # Encode jpeg_img to base64 format
        #f = base64.b64encode(f)
        # Get length of f and encode to base64
        #f_len = base64.b64encode((len(f)).to_bytes(4, byteorder='little'))
    
        f_len = base64.b64encode((len(f)).to_bytes(4, byteorder='little'))
    
        # Send the length first - so the server knows how many bytes to expect.
        s.sendall(f_len) # Send 8 bytes (assumption: b64encode of 4 bytes will be 8 bytes due to the automatic padding feature).
    
        s.sendall(f)
    
    s.close()
    

    Server:

    import socket
    import numpy as np
    import cv2
    import base64
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("127.0.0.1", 60124))
    s.listen(5)
    c, a = s.accept()
    
    while True:
        # Read 8 bytes that tells the length of encoded image to be expected.
        data = c.recv(8)
    
        if len(data) != 8:
            break
    
        # Decode f_len from base64
        f_len = base64.decodebytes(data)
    
        # Convet from array of 4 bytes to integer value.
        f_len = int.from_bytes(f_len, byteorder='little')
    
        #f = c.recv(1024)
        # Receive the encoded image.
        data = c.recv(f_len)
    
        if len(data) != f_len:
            break
    
        #x = base64.decodebytes(data)  # Decode base64
        #x = np.fromstring(x , np.uint8)
        x = np.fromstring(data, np.uint8)
        var = cv2.imdecode(x, cv2.IMREAD_COLOR)
    
        if var is None:
            print('Invalid image')
        else:
            cv2.imshow("Camera" , var)
            cv2.waitKey(100)
    
    s.close()
    cv2.destroyAllWindows()