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

Unity中C#通过WebSocket发送WAV文件报OperationAborted错误求助

Unity C#客户端与Node.js Socket.IO服务器传输WAV文件失败:OperationAborted错误解决

核心问题:协议不匹配

你遇到的问题根源很明确:客户端用原生TCP Socket直接发数据,但服务器是基于Socket.IO搭建的。Socket.IO在WebSocket基础上封装了自定义协议层,必须先完成握手、遵循它的消息格式才能通信,原生TCP直接发二进制数据根本不会被服务器识别,连接会被强制中断,这就是你看到的OperationAborted错误的原因。

另外客户端代码还有两个关键bug:

  • WAV文件读取逻辑错误:ConvertWAVtoByteArray里用audioSource.clip.samples + HEADER_SIZE作为数组长度,这完全不合理——WAV文件的实际大小是文件本身的字节数,不是音频样本数加头大小,会导致数组长度要么不够(截断数据)要么多余(填充无效数据)。
  • 异步发送后立刻关闭Socket:SendAsync是异步操作,你在finally块里直接关闭Socket,此时数据可能还没发完,直接终止了发送操作,也会触发OperationAborted。

修正方案

1. 客户端改用Socket.IO的C#客户端库

Unity里可以用第三方的SocketIOClient库(支持.NET/Unity,兼容性好),先在Unity Package Manager中导入对应包,或通过NuGet添加引用。

修改后的客户端代码示例:

using UnityEngine;
using SocketIOClient;
using System.IO;

public class WebSocketController : MonoBehaviour
{
    [SerializeField] private AudioSource microphoneSource;
    private SocketIO _socket;

    private async void Start()
    {
        string url = "http://localhost:3000"; // Socket.IO客户端用http开头,内部自动转WebSocket
        string filePath = "C:/Users/eduar/AppData/LocalLow/Richard J/Sound Recorder/Audio_2023_04_05_23_47_56_2845.wav";
        
        // 初始化Socket.IO客户端
        _socket = new SocketIO(url);
        
        // 监听连接成功事件
        _socket.OnConnected += async (sender, e) =>
        {
            Debug.Log("连接服务器成功");
            // 直接读取WAV文件的全部字节
            byte[] wavData = File.ReadAllBytes(filePath);
            
            // 发送符合服务器预期的消息格式
            await _socket.EmitAsync("audio", new 
            {
                timeMillis = System.DateTime.Now.Ticks,
                data = wavData
            });
            
            Debug.Log("WAV文件已发送");
        };
        
        // 监听错误事件
        _socket.OnError += (sender, e) =>
        {
            Debug.LogError("Socket错误: " + e.Message);
        };
        
        // 开始连接
        await _socket.ConnectAsync();
    }

    private void OnDestroy()
    {
        // 退出时关闭连接
        _socket?.DisconnectAsync();
    }
}

2. 服务器端优化(可选,增强稳定性)

你的Node.js服务器逻辑基本没问题,添加错误处理和目录检查可以避免意外崩溃:

const express = require('express');
const fs = require('fs')
const path = require('path')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server,{maxHttpBufferSize: 1e7})

// 确保videos目录存在,避免写入失败
const videosDir = path.join(__dirname, "videos");
if (!fs.existsSync(videosDir)) {
    fs.mkdirSync(videosDir);
}

io.on('connection', function (socket) {
  console.log("客户端已连接:", socket.id)
  socket.on('audio', async function (msg) {
      try {
          var date = new Date(msg.timeMillis);
          // 替换文件名里的非法字符,避免写入失败
          const fileName = `${date.toString().replace(/[:/]/g, '-')}.wav`;
          await fs.promises.writeFile(path.join(videosDir, fileName), msg.data, "binary");  
          console.log("WAV文件已保存:", fileName)
          // 给客户端发送保存成功的确认
          socket.emit('audioSaved', { success: true, fileName });
      } catch (err) {
          console.error("保存文件失败:", err);
          socket.emit('audioSaved', { success: false, error: err.message });
      }         
  });

  socket.on('disconnect', () => {
      console.log("客户端已断开连接:", socket.id)
  });
});

server.listen(3000)
console.log("服务器运行在端口: 3000")

3. 关键注意事项

  • 确保Unity客户端的Socket.IO版本和服务器端版本兼容(比如服务器用4.x,客户端也用对应版本的库)。
  • 不要在异步操作未完成时关闭Socket,必须等发送确认或连接断开后再清理资源。
  • WAV文件读取直接用File.ReadAllBytes即可,无需手动计算长度,避免出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:02:46