我想要一种基于分隔符分割传入数据流的内存高效且省时的方法。流是网络流,进入的“消息”由CRLF
分割。以前我已经通过使用UTF8将incomming数据转换为字符串,然后检查CRLF,如果它存在我基于此分割,但是,这不是解决问题的一种非常好的方法,因为越来越多的消息是传入。另外,我可能会得到包含1条消息的数据块,并且我可能会得到包含10条消息的datachunks,甚至还有一些只包含部分消息的消息。
所以这就是我到目前为止所想到的。将内存流用于缓冲区,当数据进入时将数据读入内存流。如果我找到了分隔符(CRLF),我会获取内存流中的所有数据,然后调用messageReceived,然后继续。有什么想法吗?
[编辑]
好吧,我想我需要更好地解释我想做什么。使用的协议是IRC-protocoll,它发送“消息”或“命令”,如果你想要,由CRLF
分隔。我在C#中使用带有BeginReceive和EndReceive的套接字类,所以一切都运行异步。我正在编写的类称为MessageConnection。它从tcp-socket接收数据,每当找到给定的分隔符时(在这种情况下为CRLF
),我希望它调用一个名为OnMessage的函数,将接收的消息作为参数。我在使用StringBuilder作为缓冲区之前解决了完全相同的问题,并在每次收到数据时将新字符串附加到StringBuilder,然后我根据分隔符拆分StringBuilder返回的字符串,清空StringBuilder,以及插入拆分操作的最后一部分。之后,我循环使用split-array(没有最后一个元素)并调用OnMessage。这种方式感觉就像是一种解决问题的低效方式,因为我对字符串进行了大量的转换 - 据说不是很好,所以我想,需要有一种简单的方法来解决这个问题而不必在字符串中思考,只在字节数组中,只有在我有一个表示实际“消息”的字节数组时才转换为字符串,这就是我想要的帮助。
答案 0 :(得分:1)
我认为你确实有正确的想法。只需使用字节数组即可。
以下是我如何做,纯粹未经测试,可以优化....
byte[] m_LongBuffer;
byte[] m_SmallBuffer;
void ReceiveCallback(IAsyncResult iar)
{
//m_SmallBuffer contains the data read from the stream
//Append it to m_LongBuffer
int bytesread = socket.EndReceive(iar);
m_LongBuffer = m_LongBuffer.Concat(m_SmallBuffer.Take(bytesread)).ToArray();
int startpoint = 0;
int splitpoint = 0;
int lastendpoint = 0;
bool twochar = false;
do
{
for(int i=0;i<m_LongBuffer.Length;++i)
{
if((m_LongBuffer[i] == 0x0A) || (m_LongBuffer[i] == 0x0D))
{
splitpoint = i;
if((m_LongBuffer[i+1] == 0x0A) || (m_LongBuffer[i+1] == 0x0D))
twochar=true;
else
twochar=false;
lastendpoint = splitpoint;
String message = ASCII.ASCIIEncoding.GetString(m_LongBuffer.Skip(startpoint).Take(splitpoint - startpoint).ToArray());
//Do something with the message
startpoint = splitpoint + (twochar ? 2 : 1);
break;
}
}
if(i >= m_LongBuffer.Length)
splitpoint = -1;
} while (splitpoint != -1);
m_LongBuffer = m_LongBuffer.Skip(lastendpoint).ToArray();
}
答案 1 :(得分:0)
我不得不做一段时间这样的事情。我通过创建生产者/消费者流来解决它。生产者(在您的情况下,读取网络流的东西)将字节写入流,并且消费者创建连接到流的StreamReader
。
当然,这需要消费者使用另一个线程,但它可以防止在回调时间过长而你最终丢失消息时可能出现的问题。
我写了一个流,我在一篇文章中称之为ProducerConsumerStream
。请参阅http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=852。
此问题的先前解决方案涉及自己解析字节数组。这很有效,但不像这种流方法那么灵活。