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
相关产品推荐
相关产品推荐

