You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中通过Socket发送图片、音视频等非基础数据类型

用Python Socket发送图片、音视频等二进制数据的实现方案

嘿,这个问题我之前做项目的时候刚好碰到过!其实socket本身就是基于字节流传输的,不管是字符串还是图片、视频这类可视化数据,本质上都要转成bytes类型来发送——和你想的沿用字符串发送逻辑的思路完全一致,只是处理二进制文件的方式略有不同,不用复杂的类型转换函数,直接操作字节流就好。

核心思路

所有非文本类的二进制文件(JPG/MP4/AVI等)本身就是由字节组成的,所以我们不需要像字符串那样用encode()转码,只需要以二进制模式读取文件,然后直接通过socket发送字节流就行;接收端则把收到的字节流写入文件即可。

不过要注意:如果是大文件(比如几百MB的视频),不能一次性把整个文件读入内存再发送,必须分块处理,否则会占用过多内存甚至导致程序崩溃。另外,为了避免socket粘包问题,最好先发送文件的大小,让接收端知道需要接收多少字节的数据。

具体实现示例

1. 发送/接收单张图片(小文件)

服务端(发送图片)

import socket
import struct

def send_image():
    # 创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(('localhost', 12345))
    server_socket.listen(1)
    print("等待客户端连接...")
    
    conn, addr = server_socket.accept()
    print(f"已连接:{addr}")
    
    # 以二进制模式读取图片
    with open("test.jpg", "rb") as f:
        image_data = f.read()
    
    # 先发送图片大小(用struct转成固定4字节的大端模式整数)
    conn.send(struct.pack('!I', len(image_data)))
    # 发送图片数据(sendall确保所有字节发送完成)
    conn.sendall(image_data)
    
    print("图片发送完成")
    conn.close()
    server_socket.close()

if __name__ == "__main__":
    send_image()

客户端(接收图片)

import socket
import struct

def receive_image():
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('localhost', 12345))
    
    # 先接收图片大小(固定4字节)
    size_data = client_socket.recv(4)
    image_size = struct.unpack('!I', size_data)[0]
    
    # 循环接收图片数据,直到收满指定大小
    received_data = b''
    while len(received_data) < image_size:
        chunk = client_socket.recv(1024)
        if not chunk:
            break
        received_data += chunk
    
    # 以二进制模式写入文件
    with open("received_test.jpg", "wb") as f:
        f.write(received_data)
    
    print("图片接收并保存完成")
    client_socket.close()

if __name__ == "__main__":
    receive_image()

2. 发送/接收大视频文件(分块处理)

对于几百MB甚至GB级的视频,分块读写是必须的,避免内存溢出:

服务端(发送视频)

import socket
import struct
import os

def send_large_file(file_path):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(('localhost', 12346))
    server_socket.listen(1)
    print("等待客户端连接以接收视频...")
    
    conn, addr = server_socket.accept()
    print(f"已连接:{addr}")
    
    # 获取文件总大小
    file_size = os.path.getsize(file_path)
    # 发送文件大小(用Q格式转成8字节大端模式整数,支持更大的文件)
    conn.send(struct.pack('!Q', file_size))
    
    # 分块发送文件,每次读4KB
    with open(file_path, "rb") as f:
        while True:
            chunk = f.read(4096)
            if not chunk:
                break
            conn.sendall(chunk)
    
    print("视频发送完成")
    conn.close()
    server_socket.close()

if __name__ == "__main__":
    send_large_file("test.mp4")

客户端(接收视频)

import socket
import struct

def receive_large_file(save_path):
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('localhost', 12346))
    
    # 接收文件大小(固定8字节)
    size_data = client_socket.recv(8)
    file_size = struct.unpack('!Q', size_data)[0]
    
    # 分块接收并写入文件,同时打印进度
    received_size = 0
    with open(save_path, "wb") as f:
        while received_size < file_size:
            chunk = client_socket.recv(4096)
            if not chunk:
                break
            f.write(chunk)
            received_size += len(chunk)
            print(f"已接收:{received_size/file_size:.2%}", end='\r')
    
    print("\n视频接收并保存完成")
    client_socket.close()

if __name__ == "__main__":
    receive_large_file("received_test.mp4")

关键细节说明

  • 二进制模式读写:打开文件时必须用rb(读二进制)和wb(写二进制)模式,不能用默认的文本模式,否则会破坏二进制文件的结构。
  • sendall()的必要性:send()可能只发送部分字节,而sendall()会循环调用send()直到所有数据都发送完毕,传输文件时优先使用它。
  • 文件大小的传输:用struct模块把整数转成固定长度的字节(比如!I对应4字节、!Q对应8字节),这样接收端能准确解析出文件总大小,避免粘包问题。
  • 分块大小调整:分块大小可以根据实际网络情况调整,4KB-8KB是比较通用的选择,太大可能导致传输卡顿,太小则会增加IO次数。

内容的提问来源于stack exchange,提问作者janjanjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:36:41