C#流套接字,如何分隔消息?

有点长的头衔,但无论如何……

我一直在研究这些例子,特别是关于写入和读取字节流的消息大小的部分
http://doc.trolltech.com/4.4/network-fortuneclient-client-cpp.html
http://doc.trolltech.com/4.4/network-fortuneserver-server-cpp.html

但我似乎无法在C#中弄明白。

StreamWriter writer = new StreamWriter(tcpClient.GetStream()); writer.Write(data.Length + data); 

这根本不起作用。 有人能给我一个正确方向的推动吗?

通常你会先发送长度。 两端应该就长度的长度达成一致 – 例如,您可能乐意使用固定的4字节长度前缀作为二进制:

  byte[] data = ... int len = data.Length; byte[] prefix = Bitconverter.GetBytes(len); stream.Write(prefix, 0, prefix.Length); // fixed 4 bytes stream.Write(data, 0, data.Length); 

显然调用者需要做同样的事情 – 即读取前4个字节以获得长度。 对于阅读,接收器应注意不要读取太多数据。 一种方法是使用限制流 – 例如, 此类可用于获取不会读取太多的Stream。

如果您不希望总是发送4个字节的开销,那么可能会有一些更有趣的编码 – 例如,使用msb作为延续块。

有关信息, protobuf-net是一个围绕谷歌的“协议缓冲”基于消息的格式设计的二进制序列化器。 它为您处理了很多细节,如果您不想花费大量时间编写序列化代码,可能会感兴趣。 QuickStart项目中有套接字的示例, 例如此处

而不是data.Length ,尝试:

 writer.Write(chr(data.Length) + data); 

这将在每个数据块前面加上一个字节,表示其长度(最长255个字节)。 按照您的要求,这只是一个轻推。 🙂

更新:我只记得C#是所有Unicode和东西,所以chr()可能会给你多个字节。 调整以适应。

我想这应该这样做:(我假设你的数据是一个字符串)

 Stream stream = tcpClient.GetStream();
编码编码= Encoding.GetEncoding(“编码名称”);

 byte [] bytes = encoding.getBytes(data);

 stream.Write(BitConverter.GetBytes((短)bytes.Length),0,2);  //希望数据不会超过64k
 stream.Write(字节,0,bytes.Length);

当你说“这根本不能很好地工作”时,我会特别好奇什么是行不通的。 它们是套接字两端的.NET应用程序吗? 如果是这样,请忽略此答案。 如果没有,那么问题可能是整数的字节顺序? 一个小端和大端问题? 这个post在这里讨论它:

http://bytes.com/forum/thread225649.html

http://books.google.com/books?id=2zT5b2BS1OUC&pg=PA64&lpg=PA64&dq=c%23+sockets+integers+byte+ordering&source=web&ots=_ISzZZ6HHT&sig=tUHdNT0NGv0uxusmHG9YjFw6j9k&hl=en&sa=X&oi=book_result&resnum=2&ct=result

如果两端都不是.NET的另一个问题可能是另一端需要ANSI字符串,而您正在发送Unicode。

您也可以,如果您想保留它的明文,请指定特定的最大大小,并通过string.Format填充数字。 (例如,假设只允许4个字符的长度)这避免了有用数据流中的数字问题,并简化了解码。

最后一个明文解决方案是在长度和数据之间放置一个特定字符,例如 – ,然后一次抓取一个字符,直到你达到减号,解码检索到的字符串(忽略当然的减号),然后用它来确定剩余字符串的长度,以及您需要更改的输出代码,以便在其间添加该字符。

使用WriteLine而不是Write,ReadLine而不是Read …

如果您正在谈论发送纯文本消息,请在消息末尾添加换行符。 然后,读取字节,直到遇到此换行符并将字节转换为字符串。 为方便起见,任何System.IO.StreamReader和System.IO.StreamReader都在单个方法(WriterLine或ReadLine)writer.WriteLine(“Line to send”)中实现此行为; string lineSent = reader.ReadLine();