我正在研究客户端/服务器应用程序 服务器有时会向所有连接的客户端发送一个字符串。
为此,我定义了一个数据包:
byte< - packet id
int< - 字符串的长度
byte []< - 包含字符串
现在我如何发送这个数据包:
byte[] buf = { ID };
buf = buf.Concat(BitConverter.GetBytes(StringData.Length)).ToArray();
buf = buf.Concat(Encoding.UTF8.GetBytes(StringData)).ToArray();
stream.Write(buf, 0, buf.Length);
有时字符串非常小(大约200字节),但有时它更大(> 20k字节)。通常较小的数据包在客户端读取时没有问题,但较大的数据包仅部分由客户端接收 客户端上的典型场景:
packet id -> 0x01
length -> 20000
string -> "this is an example stri"
我知道“这是一个示例字符串”不是20000字节长,但它只是一个例子
在我的例子中,字符串是一个序列化的JObject(Json.Net)。
在客户端,我读了这样的数据包:
byte[] buf = new byte[1];
stream.Read(buf, 0, buf.Length);
// Some packet id evaluation
buf = new byte[4];
stream.Read(buf, 0, buf.Length);
int length = BitConverter.ToInt32(buf, 0);
buf = new byte[length];
stream.Read(buf, 0, length);
string jsonString = Encoding.UTF8.GetString(buf, 0, length);
我真的不知道我做错了什么 有什么建议在哪里寻找错误或者我在发送数据时做错了什么?
提前致谢!
答案 0 :(得分:2)
代码有两个问题:
首先,您使用字符串的长度而不是数据包中编码数据的长度。首先转换字符串,以便您可以使用数据包中的长度:
byte[] data = Encoding.UTF8.GetBytes(StringData);
byte[] buf = { ID };
buf = buf.Concat(BitConverter.GetBytes(data.Length)).ToArray();
buf = buf.Concat(data).ToArray();
其次,Read
方法不保证它返回请求的字节数。它可以在缓冲区中放置更少的字节,并返回实际放入缓冲区的字节数。
使用Read
调用的返回值来检查是否需要多次调用它来获取数据。例如:
buf = new byte[4];
int offset = 0;
while (offset < buf.length) {
int len = stream.Read(buf, offset, buf.Length - offset);
offset += len;
}
注意:此实现不处理流过早结束的情况。然后Read
方法将返回零,并且代码进入永久循环。您可能希望创建一个方法来从流中读取,从而处理所有可能的错误。
答案 1 :(得分:0)
我无法保证这会有效,但请试一试,以便阅读您的数据:
var ms = new System.IO.MemoryStream();
byte[] buffer = new byte[4096];
int bytesRead = 0;
do
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, bytesRead);
}
while (stream.DataAvailable);
string jsonString = System.Text.Encoding.UTF8.GetString(ms.ToArray());
根据您的需要进行调整。让我知道它是如何工作的。