我正在使用C#通过TCP连接读取连续的数据流(ITCH数据,即外汇价格),但在运行应用程序较长时间后,应用程序有时会丢弃数据包并且信息丢失。
以下是我用来读取数据的代码段:
private void ReaderThreadStarter()
{
StreamReader streamReader = new StreamReader(this._networkStream);
while (!_stopping)
{
try
{
if (this._networkStream.DataAvailable)
{
while ((line = streamReader.ReadLine()) != null)
{
lock (_queue.ConcurrentQueue)
{
byte[] data = System.Text.Encoding.ASCII.GetBytes(line);
Log.Info("Data Added in Queue: " + Encoding.ASCII.GetString(data, 0, data.Length));
_queue.WriteToQueue(data);
}
}
}
}
catch (Exception exception)
{
Log.Error(exception);
}
finally
{
SetStopped();
}
}
}
上面的代码所做的是它从TCP连接读取数据并将其写入并发队列,然后另一个线程使用队列中的数据进行处理。所以基本上只是一个生产者 - 消费者问题。
生产者 - 消费者部分似乎工作正常,因为我在队列中写的内容被消费者使用。
一种选择是使用嗅探器并确认应用程序正在丢弃数据包,但我正在一个我无法使用嗅探器的环境中工作。我认为存在数据包丢失的原因是因为对于我的一些外汇订单,我从未获得取消和价格下降,数据提供商告诉我价格在那时是正确的。
我还记录了在保存到队列之前从TCP端口读取的数据,因此从日志中我假设数据在从连接读取时丢失。
有人可以告诉我这里可能做错了什么,或者丢弃数据包的原因是什么。
以下是我的消费者代码的代码段:
public void ReadQueue()
{
try
{
while (true)
{
{
byte[] data = _queue.ReadFromQueue();
Parse(data);
}
}
}
catch (Exception exception)
{
Log.Error(exception);
}
}
public byte[] ReadFromQueue()
{
try
{
byte[] data;
lock (this) // Enter synchronization block
{
ConcurrentQueue.TryDequeue(out data);
}
return data;
}
catch (Exception exception)
{
Log.Error(exception);
return null;
}
}
答案 0 :(得分:7)
有两件事让我眼前一亮;首先是你使用DataAvailable
。使用它 几乎从不 正确的做法。这个有用的主要时间是在同步和异步方法之间进行选择。它会 不 告诉您是否有更多数据是入站的,例如,并且可能会给出“误报”(因为您使用的是它并不意味着什么)导致你的循环过早退出。 DataAvailable
仅告诉您当前缓冲区中是否有数据,这就是它告诉您的所有内容。
我感兴趣的第二件事是data
是二进制还是文本。您使用StreamReader
的事实建议使用文字,但之后......为什么要将其重新编码回byte[]
?如果是任意二进制文件,则无法将其作为文本处理 - 将无法正常工作。当您通过StreamReader
提取时,已经损坏了内容。如果它是基于文本的协议,请不要重新编码:使用字符串队列(或类似的)。
在不相关的注释中......如果队列真正是并发,您可能不需要同步访问。