1

在我的静态类中,我有这个:

static var cache = new ConcurrentDictionary<string, object>();

在线程 #1 我这样做:

cache.TryAdd (stringFromSomewhere, newlyCreatedObject); 
Console.WriteLine(stringFromSomewhere); // Outputs "abc"

在 Thread #1 之后几秒钟,在 Thread #2 中:

if(cache.ContainsKey(stringFromSomewhereElse))
    Console.WriteLine("Yes, it exists.");
else
    Console.WriteLine("This did not exist: " + stringFromSomewhereElse);

它输出“这不存在:abc”

然后在线程 #2 之后的线程 #3 中:

foreach(var kvp in cache)
{
    Console.WriteLine("string: " + kvp.Key);
    if(cache.ContainsKey(kvp.Key))
        Console.WriteLine("Yes, it exists.");
    else
        Console.WriteLine("This did not exist: " + kvp.Key);
}

我得到输出“字符串:abc”和“是的,它存在”。

在 Thread #1 中,我使用 MD5 创建字符串,如下所示:

Convert.ToBase64String (md5.ComputeHash(Encoding.ASCII.GetBytes(value)))

在线程#2 中,我从字节流中获取字符串,其中字符串是使用 UTF8 编码写入的,然后再次使用 UTF8 编码从字节中读取字符串。

在线程#3 中,我通过循环 ConcurrentDictionary 来获取字符串。

我在这里想念什么?据我所知,线程#2 的行为应该与线程#3 一样。

我有两种可能性,在我看来这两种可能性都很大:

  • 这是我不知道的某种同步问题吗?
  • 或者字符串以某种方式不同?当我将它输出到控制台时,它没有什么不同。

任何人有任何其他想法或解决方案?

编辑:

我像这样将数据写入流:

string data = System.Web.HttpUtility.UrlEncode(theString);
byte[] buffer = Encoding.UTF8.GetBytes (data);
NetworkStream stream = client.GetStream(); // TcpClient client;
stream.Write (buffer, 0, buffer.Length);

然后我像这样从流中读取数据:

string data = "";
NetworkStream stream = client.GetStream(); // TcpClient client;
byte[] bytes = new byte[4096];
do {   
    int i = stream.Read (bytes, 0, bytes.Length);
    data += Encoding.UTF8.GetString (bytes, 0, i);
} while(stream.DataAvailable);
string theString = HttpUtility.UrlDecode(data);
4

2 回答 2

1

如果您将字节写入网络流然后将它们读回,则必须在数据前面加上一个表示后面有多少字节的值,或者您需要一个数据结束标记。根据您的代码编写方式,接收代码很可能只获取部分数据。

例如,想象一下您的密钥是“HelloWorld”。您的发送代码将字符串发送出去。接收代码看到缓冲区中的“Hello”部分,抓住它,检查是否有更多数据可用,这不是因为网络传输线程还没有完成将其复制到缓冲区。

所以你只得到字符串的一部分。

可能发生的另一件事是您阅读过多。如果您将两个字符串写入网络流并且您的阅读器读取它们,就好像它们是单个字符串一样,就会发生这种情况。

要做到这一点,你应该这样做:

int dataLength = buffer.Length;
byte[] lengthBuff = BitConverter.GetBytes(dataLength);
stream.Write(lengthBuff, 0, lengthBuff.Length);  // write length
stream.Write(buffer, 0, buffer.Length);  // write data

然后通过首先读取长度然后从流中读取那么多字节来读取它。

或者,您可以使用数据结束标记:

stream.Write(buffer, 0, buffer.Length);  // write data
buffer[0] = end_of_data_byte;
stream.Write(buffer, 0, 1);  // write end of data

并且您的阅读器读取字节,直到它获得数据标记的结尾。

用于数据结束标记的内容取决于您。它应该是不会出现在正常数据流中的东西。

就个人而言,我会选择长度前缀。

于 2013-07-02T00:14:24.910 回答
0

很难理解你的问题的流程 - 但是我注意到一件事:你在网络 Write() 之后 Flush() 吗?否则,您可能会延迟写入,这通常会导致与时序相关的问题。

于 2013-07-02T04:20:27.050 回答