异步套接字,接收字符串消息

时间:2011-07-21 10:52:17

标签: c# multithreading string sockets console

晚上好,提前抱歉写了这么多,但我不知道错误在哪里......

我的客户端应用程序是异步从服务器接收的。我想一次传输一堆东西(数组的内容,几百个字节)。

我希望服务器能够发送“命令”,并且在客户端有一个功能根据这些命令行动,例如,如果来自服务器的消息显示"print_hello",它应该调用一个函数打印你好。

现在,我的理解是,当异步接收数据时,我不知道已经发送了多少数据(或者是否发送了超出我预期的数据),所以我需要将所有数据存储在缓冲区,当收到“结束命令”(例如,'!')符号时,它应该知道调用该函数。

到目前为止,这对我来说很有意义,但我在实施它时遇到了麻烦。在我的DataReceived回调函数中,我有这段代码:

Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);

mainBuffer声明为volatile static string mainBuffer = ""; 第一行正确打印,并按预期方式遍历所有数据。但是,当我打印出mainBuffer时,它只会打印出我收到的第一组数据,其余的数据不会被添加到缓冲区中。

是什么导致这个?线程安全问题?我没有读过mainBuffer的最新值吗?我不能使用断点来调试它。

示例输出:

Raw data: ABC
ABC
Raw data: DEF
ABC
RAW data: GHI
ABC

小更新,我也尝试使用volatile static int,并在每个DataReceived()后递增并正确打印。但是字符串仍然没有更新。

1 个答案:

答案 0 :(得分:3)

这是你的问题“乱码代码行!”

//of course the problem has noting to do with the string being volatile...
private volatile string mainBuffer = string.Empty;

byte[] buffer = new byte[1024];

while (networkStream.Read(buffer, 0, buffer.Length) > 0)
{
    string data = System.Text.Encoding.UTF8.GetString(buffer);
    Console.WriteLine("Raw data: {0}", data));
    mainBuffer += data;
    Console.WriteLine(mainBuffer);
}

自然地,此代码的输出将如您之前提到的那样。以下是发生的事情:

C#中的string类是一个char数组,由指向数组中第一个char的指针开始,以特殊的“终端”字符\0结束。
当您创建n索引的字节数组时,它将使用byte的默认值0填充数组的所有索引。但是0等于终端字符\0

byte b = (byte)`\0`;\\the value of b will be 0

因此,当您调用Read(buffer)时,该方法不会修剪缓冲区,只是适合读取的数据。因此,如果缓冲区大小“此处为1024”大于读取的数据,则缓冲区的所有剩余字节将等于终端字符'\ 0',因此生成的字符串的字符数组将为{{1} }。当您向其添加字符串ABC\0\0\0\0... to the index 1024时,它会将DEF数组的最后一个索引添加到最后char之后“,\0数组将为{{ 1}},但由于char被添加到终端字符之后,因此ABC\0\0\0\0...DEF将忽略所有DEF之后的所有内容。

另外请注意,在调试时,如果将鼠标指向Console.Write变量,您会看到它包含的实际数据可能是\0

但是要解决问题并仅生成可靠的字符串,请获取读取的实际字节数并仅从中生成字符串。所以:

mainBuffer

在此提及您应该考虑使用StringBuilder代替ABC\0\0\0\0..DEF\0\0\0\0..GHI