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

WinError 10038错误排查:MediaPipe向Unity传输姿态数据失败

TCP Socket连接报错WinError 10038:尝试对非套接字执行操作

我在尝试通过TCP Socket将MediaPipe姿态估计的数据发送到Unity时,客户端出现WinError 10038错误(尝试对非套接字执行操作)。以下是客户端Python代码和服务器端Unity C#代码:

客户端Python代码

import socket
import PoseEstimation as pm
import cv2

host, port = "127.0.0.1", 25001
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
cap = cv2.VideoCapture(0)
detector = pm.PoseEstimatior()

def sendData(lmString, sock, host, port):
    #sock.connect((host, port))
    sock.send(lmString.encode("utf-8"))
    response = sock.recv(1024).decode("utf-8")
    print(response)
    #sock.close()

while cap.isOpened():
    _, img = cap.read()
    img = detector.findPose(img)
    lmList, complete = detector.getPosition(img)
    lmString = ','.join([','.join(map(str, inner_list)) for inner_list in lmList])
    
    if complete:
        sendData(lmString, sock, host, port)

    cv2.imshow("Image", img)
    
    if cv2.waitKey(1) == ord('q'):
        break
sock.close()
cap.release()
cv2.destroyAllWindows()

服务器端Unity C#代码

using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using System.Threading;
using System.Linq;

public class MyListener : MonoBehaviour
{
    Thread thread;
    public int connectionPort = 25001;
    TcpListener server;
    TcpClient client;
    bool running;
    public GameObject[] Body;
    Vector3[] position = Enumerable.Repeat(Vector3.zero, 33).ToArray();

    void Start()
    {
        // 单独线程接收数据,避免Unity卡顿
        ThreadStart ts = new ThreadStart(GetData);
        thread = new Thread(ts);
        thread.Start();
    }

    void GetData()
    {
        // 创建服务器
        server = new TcpListener(IPAddress.Any, connectionPort);
        server.Start();

        // 获取客户端连接
        client = server.AcceptTcpClient();

        // 开始监听
        running = true;
        while (running)
        {
            Connection();
        }
        server.Stop();
    }

    void Connection()
    {
        // 读取网络流数据
        NetworkStream nwStream = client.GetStream();
        byte[] buffer = new byte[client.ReceiveBufferSize];
        int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);

        // 解码为字符串
        string dataReceived = Encoding.UTF8.GetString(buffer, 0, bytesRead);

        // 过滤空字符串
        if (dataReceived != null && dataReceived != "")
        {
            // 解析数据格式
            position = ParseData(dataReceived);
            nwStream.Write(buffer, 0, bytesRead);
        }
    }

    // 自定义数据解析函数,需匹配发送端格式
    public static Vector3[] ParseData(string dataString)
    {
        Debug.Log(dataString);

        // 分割数据为数组
        string[] stringArray = dataString.Split(',');
        Vector3[] vectors = new Vector3[33];

        for (int i = 0; i < 33; i++)
        {
            float x = float.Parse(stringArray[1 + (i * 4)]) / 100;
            float y = float.Parse(stringArray[2 + (i * 4)]) / 100;
            float z = float.Parse(stringArray[3 + (i * 4)]) / 100;
            vectors[i] = new Vector3(x, y, z);
        }

        return vectors;
    }

    void Update()
    {
        // 更新场景中物体位置
        for (int i = 0; i < 33; i++)
        {
            Body[i].transform.localPosition = position[i];
        }
    }
}

错误原因及修复方案

WinError 10038本质是操作了失效的套接字对象,以下是针对性修复:

  1. 客户端添加连接异常处理
    当服务器断开连接时,客户端套接字会失效,需捕获异常并重新连接:

    def sendData(lmString, sock, host, port):
        try:
            sock.send(lmString.encode("utf-8"))
            response = sock.recv(1024).decode("utf-8")
            print(response)
        except (BrokenPipeError, ConnectionResetError, socket.error) as e:
            print(f"连接失效,重新连接: {e}")
            sock.close()
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((host, port))
            sock.send(lmString.encode("utf-8"))
            response = sock.recv(1024).decode("utf-8")
            print(response)
        return sock
    
    # 主循环中更新套接字对象
    if complete:
        sock = sendData(lmString, sock, host, port)
    
  2. 服务器端优化连接逻辑
    当前服务器仅处理一次连接,断开后无法重新接收,需修改为循环等待新连接:

    void GetData()
    {
        server = new TcpListener(IPAddress.Any, connectionPort);
        server.Start();
        running = true;
        while (running)
        {
            try
            {
                client = server.AcceptTcpClient();
                while (running && client.Connected)
                {
                    Connection();
                }
            }
            catch (SocketException)
            {
                client?.Close();
            }
        }
        server.Stop();
    }
    
    void Connection()
    {
        if (!client.Connected) return;
        try
        {
            NetworkStream nwStream = client.GetStream();
            if (!nwStream.CanRead) return;
            byte[] buffer = new byte[client.ReceiveBufferSize];
            int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
            if (bytesRead <= 0)
            {
                client.Close();
                return;
            }
            string dataReceived = Encoding.UTF8.GetString(buffer, 0, bytesRead);
            if (!string.IsNullOrEmpty(dataReceived))
            {
                position = ParseData(dataReceived);
                nwStream.Write(buffer, 0, bytesRead);
            }
        }
        catch (IOException)
        {
            client.Close();
        }
    }
    
  3. 验证数据格式一致性
    确保MediaPipe输出的姿态数据符合服务器解析逻辑(33个关键点,每个点4个数值),避免因数据错误导致连接中断:

    lmString = ','.join([','.join(map(str, inner_list)) for inner_list in lmList])
    # 验证数据段数量是否为33*4=132
    if len(lmString.split(',')) == 132 and complete:
        sock = sendData(lmString, sock, host, port)
    else:
        print("姿态数据格式错误,跳过发送")
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 13:33:19