python 中通过 TCP 套接字传输视频的代码;需要帮助理解其中的一部分

Code for streaming video over tcp socket in python; need help understanding parts of it

我得到了将视频从客户端流式传输到服务器的代码:

客户:

import cv2, imutils
import mss
import numpy
from win32api import GetSystemMetrics
import pickle
import socket, struct

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = "IPADRESS"
port = 9999
client_socket.connect((host_ip,port))

with mss.mss() as sct:
    monitor = {"top": 0, "left": 0, "width": GetSystemMetrics(0), "height": GetSystemMetrics(1)}
    while True:
        img = numpy.array(sct.grab(monitor))
        frame = imutils.resize(img, width=1400)
        a = pickle.dumps(frame)
        message = struct.pack("Q",len(a))+a
        client_socket.send(message)

服务器:

import cv2, imutils
import numpy as np
import pickle, struct
import socket
import threading

server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host_ip = "IP_ADRESS"
port = 9999
socket_address = (host_ip,port)
server_socket.bind(socket_address)
server_socket.listen()
print("Listening at",socket_address)

def show_client(addr,client_socket):
    try:
        print('CLIENT {} CONNECTED!'.format(addr))
        if client_socket: # if a client socket exists
            data = b""
            payload_size = struct.calcsize("Q")
            while True:
                while len(data) < payload_size:
                    packet = client_socket.recv(4*1024)
                    if not packet: 
                        break
                    data+=packet
                packed_msg_size = data[:payload_size]
                data = data[payload_size:]
                msg_size = struct.unpack("Q",packed_msg_size)[0]
                while len(data) < msg_size:
                    data += client_socket.recv(4*1024)
                frame_data = data[:msg_size]
                data  = data[msg_size:]
                frame = pickle.loads(frame_data)
                cv2.imshow("Screen", frame)
                key = cv2.waitKey(1) & 0xFF
                if key  == ord('q'):
                    break
            client_socket.close()
    except Exception as e:
        print(e)
        print(f"CLINET {addr} DISCONNECTED")
        pass

while True:
    client_socket,addr = server_socket.accept()
    thread = threading.Thread(target=show_client, args=(addr,client_socket))
    thread.start()
    print("TOTAL CLIENTS ",threading.activeCount() - 1)

很多代码来自一个名为“pyshine”的 youtuber,一切正常,但我不明白,这段代码的特定部分到底在做什么。 这些是部分:

首先在客户端代码中:

message = struct.pack("Q",len(a))+a

我知道它会根据泡菜的长度做一些事情,并且会在上面附加泡菜,但不会更多。

服务器代码中的第二个:

            data = b""
            payload_size = struct.calcsize("Q")
            while True:
                while len(data) < payload_size:
                    packet = client_socket.recv(4*1024)
                    if not packet: 
                        break
                    data+=packet
                packed_msg_size = data[:payload_size]
                data = data[payload_size:]
                msg_size = struct.unpack("Q",packed_msg_size)[0]
                while len(data) < msg_size:
                    data += client_socket.recv(4*1024)
                frame_data = data[:msg_size]

随着打印出一些值,我肯定理解得更好了,但是整个过程,它是如何得到最终的“frame_data”的,对我来说仍然是个谜。所以,如果有人能向我解释那里的过程,我将不胜感激。

socket 是原始对象,它不关心你发送什么数据。您可以发送两个帧,客户端可以将其作为单个包获取,也可以将其作为多个小包获取 - socket 不关心第一个 frame 的结尾在哪里。要解决此问题,此代码首先发送 len(data),然后发送 data。它使用 struct("Q"),所以这个值 len(data) 总是 8 bytes。通过这种方式,接收器知道它必须接收多少 data 才能拥有完整的帧 - 首先它获得 8 bytes 才能获得 len(data),然后它使用该值获得所有 data。这就是第二个代码所做的——它重复 recv() 直到它得到所有 data。它还会检查它是否没有从下一帧获得 data - 并将此部分保留为 data[payload_size:] 以便在下一帧/

中使用它

如果您将在双方使用相同的规则 - 发送方首先使用 size 发送 8 bytes,然后发送 data,接收方首先使用 8 bytes size 然后得到 data(使用 size)——然后你就定义了 protocol。 (类似于其他协议:HTTPHyperText Transfer Protocol),FTPFile Transfer Protocol),SMTPSend Mail Transfer Protocol)等)