c#:使用Unicode编码从聊天的NetworkStream中读取多少字节
本文关键字:NetworkStream 读取 多少 字节 聊天 使用 Unicode 编码 | 更新日期: 2023-09-27 18:01:37
我遵循了一个使用ASCII编码发送/接收消息的聊天教程,它习惯于一行读取4096字节,然后写入聊天客户端。但是现在我已经将编码改为unicode,并且我知道unicode每个字符使用更多字节。
我的代码如下:taskOpenEndpoint = Task.Factory.StartNew(() =>
{
while (true)
{
serverStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead = 0;
try
{
bytesRead = serverStream.Read(message, 0, 4096);
}
catch (Exception ex)
{
if(flag_chiusura == false)
MessageBox.Show(ex.Message);
return;
}
UnicodeEncoding encoder = new UnicodeEncoding();
AddMessage(encoder.GetString(message, 0, bytesRead));
Thread.Sleep(500);
}
});
我应该改变字节读取的数量,现在我使用Unicode编码?
切换到Unicode肯定会对这段代码产生影响。这是错误的代码,它假设您将从套接字读取数据的"数据包"。只有在使用UDP套接字时才会出现这种情况,TCP套接字实现流。其中从套接字读取的字节数是完全不可预测的,并且与网络连接另一端传输的字节数不匹配。
你的Thread.Sleep()调用是一种变通方法。然而,这是一种极其邪恶的修复方法。首先,它被放置在错误的位置,在你阅读之后睡觉,而不是在你阅读之前。更糟糕的是,它不能保证漏洞已经被修复,如果网络另一端的应用程序也出现延迟,比如当机器负载过重时,那么你仍然无法读取"数据包"。这种情况并不经常发生,因此我们没有机会调试这个问题。而这个问题发生在千里之外的一台机器上,这当然使它完全不可能。
所以使用Unicode会增加你的应用程序崩溃的几率。当要求Encoder解码部分字节序列时将抛出。
你需要修复这个bug。删除Thread.Sleep()调用。通过首先传输数据包中的字节数,将TCP流转换为数据包流。接收方现在可以读取长度并知道循环的频率,反复调用read()直到接收到所有字节。在此之后,解码当然不会造成任何麻烦。
不需要更改协议就可以使用下面的代码:
注意:有一些记录/开始/结束的概念是很好的,而不仅仅是块大小。
taskOpenEndpoint = Task.Factory.StartNew(() =>
{
UnicodeEncoding enc = new UnicodeEncoding(false, false, false);
while (true)
{
serverStream = tcpClient.GetStream();
byte []message = new byte[16384];
int bytesRead = 0;
try {
// --------- first version may avoid blocking:
while( encoder.GetCharCount(message, 0, bytesRead) < 4096
&& bytesRead < message.Length )
{
if( serverStream.DataAvailable /* && !timed_out */ )
message[bytesRead++] = serverStream.ReadByte();
else
Thread.Sleep(10); // Better to wait than sleep...
}
// --------- second version will fully block:
while( encoder.GetCharCount(message, 0, bytesRead) < 4096
&& bytesRead < message.Length)
bytesRead += server.Read(
message,
bytesRead,
168384 - message.Length);
catch (Exception ex)
{
if(flag_chiusura == false)
MessageBox.Show(ex.Message);
return;
}
AddMessage(encoder.GetString(message, 0, bytesRead));
Thread.Sleep(500);
}
});
可以通过计算GetByteCount(decoded)并且只重新解码尚未完全解码的部分来更有效。