C# TCP流未知数据长度场景下的Unity网络数据接收方法
Unity 中TCP变长数据接收规范实现
原有实现的问题
你之前使用固定256字节缓冲区同步读取的写法存在两个核心缺陷:
- 固定长度缓冲区无法承载超过256字节的返回数据,敌人数量多、返回数据量大时会出现数据截断、溢出
NetworkStream.Read方法不会一次性读完所有待接收数据,它仅返回当前时刻可读的字节段,哪怕总数据长度小于缓冲区长度,也可能分多次返回,直接尝试读满缓冲区长度会导致线程阻塞或读取到无效的空字节填充内容
推荐实现方案
你提到的使用System.IO下的StreamWriter/StreamReader的方案是可行的,但要注意TCP是面向流的协议,没有天然的消息边界,必须和服务端提前约定消息分隔规则,否则会出现粘包问题。
方案1:分隔符法(适合文本类消息,适配StreamReader/Writer)
和服务端约定每条消息末尾固定加换行符(\n或\r\n)作为结束标记,这种场景下用StreamReader处理最简洁,不需要提前预知消息长度:
private StreamWriter _writer; private StreamReader _reader; // 注意:在TCP连接建立、NetworkStream创建完成后,只初始化一次读写器,不要每次收发都新建 public void InitNetworkStream() { // 编码必须和服务端保持一致,存在非英文字符时不要用ASCII,统一用UTF8 _writer = new StreamWriter(client.stream, System.Text.Encoding.UTF8) { AutoFlush = true // 开启自动刷新,避免数据滞留在缓冲区发不出去 }; _reader = new StreamReader(client.stream, System.Text.Encoding.UTF8); } private async void SendRequest(string message) { // 发送时每条消息末尾追加换行符作为边界 await _writer.WriteLineAsync(message); // 读取时会自动读到换行符为止,自动适配任意长度的单条消息 string response = await _reader.ReadLineAsync(); buffer = response; }
方案2:长度前缀法(通用场景,兼容二进制/文本数据)
如果消息内容本身可能包含换行符,或者传输二进制数据,更通用的方案是约定每条消息前固定发送4字节(int32类型)标识本条消息的总长度,接收端先读长度,再循环读满对应长度的内容即可:
/// <summary> /// 循环读取直到填满指定长度的缓冲区,解决NetworkStream.Read单次不读满的问题 /// </summary> private byte[] ReadExactBytes(NetworkStream stream, int needLength) { byte[] buffer = new byte[needLength]; int totalRead = 0; while (totalRead < needLength) { int currentRead = stream.Read(buffer, totalRead, needLength - totalRead); if (currentRead == 0) throw new System.Exception("服务端连接已断开"); totalRead += currentRead; } return buffer; } private string ReadVariableLengthResponse(NetworkStream stream) { // 先读取4字节的长度头,注意和服务端约定字节序,避免大小端解析错误 byte[] lengthBuffer = ReadExactBytes(stream, 4); int msgLength = System.BitConverter.ToInt32(lengthBuffer, 0); // 再读取指定长度的消息体 byte[] msgBuffer = ReadExactBytes(stream, msgLength); return System.Text.Encoding.UTF8.GetString(msgBuffer); }
注意事项
- 网络IO不要在Unity主线程做同步阻塞操作,会导致游戏帧率下降、卡顿,建议用异步方法或者独立后台线程接收数据,拿到完整消息后再派发到主线程处理游戏逻辑
- 不要每次收发消息都新建StreamWriter/StreamReader实例,会造成流状态错乱、内存泄漏,连接建立时初始化一次全局复用即可
- 收发两端的编码、字节序、消息边界规则必须完全一致,否则会出现乱码、解析失败问题
内容的提问来源于stack exchange,提问作者Remy
相关产品推荐
相关产品推荐

