【问题标题】:C# TCP data transfer with BinarySerializer使用 BinarySerializer 进行 C# TCP 数据传输
【发布时间】:2026-02-09 06:55:02
【问题描述】:

我正在尝试使用 C# TCPClient 类将我的笔记本电脑与我的独立电脑连接。

笔记本电脑正在运行一个简单的控制台应用程序并扮演服务器的角色。

PC 是 Unity 应用程序(2018.1.6f1 with .Net4.x Mono)

发送代码是

public void SendData() {
    Debug.Log("Sending data");
    NetworkStream ns = client.GetStream();
    BinaryFormatter bf = new BinaryFormatter();
    TCPData data = new TCPData(true);
    using (MemoryStream ms = new MemoryStream()) {
        bf.Serialize(ms, data);
        byte[] bytes = ms.ToArray();
        ns.Write(bytes, 0, bytes.Length);
    }
}

在笔记本电脑的项目中使用相同的代码,除了Debug.Log()Console.WriteLine()替换

我使用数据接收

public TCPData ReceiveData() {
    Debug.Log("Waiting for Data");
    using (MemoryStream ms = new MemoryStream()) {
    byte[] buffer = new byte[2048];
        int i = stream.Read(buffer, 0, buffer.Length);
        stream.Flush();
        ms.Write(buffer, 0, buffer.Length);
        ms.Seek(0, SeekOrigin.Begin);
        BinaryFormatter bf = new BinaryFormatter();
        bf.Binder = new CustomBinder();
        TCPData receivedData = (TCPData)bf.Deserialize(ms);
        Debug.Log("Got the data");
        foreach (string s in receivedData.stuff) {
            Debug.Log(s);
        }
        return receivedData;
    }
}

两边都一样,

我尝试传输的数据如下所示

[Serializable, StructLayout(LayoutKind.Sequential)]
public struct TCPData {
    public TCPData(bool predefined) {
        stuff = new string[2] { "Hello", "World" };
        ints = new List<int>() {
            0,1,2,3,4,5,6,7,8,9
        };
    }
    public string[] stuff;
    public List<int> ints;
}

自定义活页夹来自here 没有它我会得到一个装配错误

我得到Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.

现在的问题:

将此从 PC 发送到笔记本电脑 - 100% 成功率
将此从笔记本电脑发送到 PC - 20% 的成功率
(80% 是上述例外)

它“有时”怎么可能起作用?
不应该是 100% 还是 0% 吗?
如何让它工作?

谢谢

E:好的,感谢所有建议,我设法增加了成功的机会,但它仍然偶尔会失败。

我发送的数据大小“数据包”有 80% 的时间正确接收,但在某些情况下,与发送的 ~500 相比,我从 byte[] 得到的数字是 3096224743817216(非常大)。

我使用的是 Int64 数据类型。

E2:在 E1 中我分别发送数据长度数据包,现在我将它们合并,这确实正确解释了长度,但现在我无法反序列化数据......每次我收到The input stream is not a valid binary format. The starting contents (in bytes) are: 00-00-00-00-00-00-04-07-54-43-50-44-61-74-61-02-00 ...

我从流中读取前 8 个字节,剩下的“x”是数据,在服务器上反序列化它,反序列化相同的数据抛出。

E3:通过重写流处理代码来修复它,我在那里的某个地方犯了一个错误;)

【问题讨论】:

  • 您是把TCPData 放在它自己的文件中还是放在另一个.cs 文件中?这在 Unity 中很重要
  • @Programmer 是的,我做到了,但这真的很重要,因为网络与 Unity 无关吗? (这里有 Unity 标签,以防 .net 框架版本与它有关)
  • 最有可能的是从 PC 到笔记本电脑的数据作为单个数据报发送,而相反的数据被拆分为多个数据报。问题是接收端如何知道数据的末尾在哪里。为了证明我的观点,在反序列化之前检查接收到的字节数
  • @jdweng 总计 543 个字节,我收到 536 个,然后是剩下的 7 个 .. 这 7 个字节有时会出现在第一个“批次”中,这是否是 ~20% 成功的原因?感谢您为我指明方向;)
  • 正如我所说,TCP 允许路由器和服务器随机拆分数据报。您需要在消息的开头添加一个字节数,然后在收到时读取,直到获得所有字节。

标签: c# unity3d serialization tcpclient networkstream


【解决方案1】:

NetworkStream.Read() 在读取请求的字节数之前不会阻塞:

"该方法将数据读入buffer参数,返回成功读取的字节数。如果没有数据可读取,Read方法返回0。Read操作读取可用数据,最多读取多少个数据size 参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法立即完成并返回零字节。"

你必须

1) 了解您期望的字节数

2) 在 Read() 上循环,直到收到预期的字节。

如果您使用 HTTP 或 Web Sockets 等更高级别的协议,它们将为您处理此“消息框架”。如果你直接在 TCP/IP 上编码,那是你的责任。

【讨论】:

  • 所以正在发生的场景是:一方从总“y”中发送“x”量的数据,另一方立即消耗这些字节并返回,因为它没有其他东西可以接收,最后是正确的之后发送有效丢失的剩余字节?为什么它只对一侧起作用?这是我第一次玩网络。
  • Read() 中通常不会中断非常小的消息,因此方向之间的消息大小差异可以解释它,但也可能取决于其他因素。