1
var buffer = new byte[short.MaxValue];
var splitString = new string[] {"\r\n"};
while (_tcpClient.Connected)
{  
  if (!_networkStream.CanRead || !_networkStream.DataAvailable)
    continue;

  var bytesRead = _networkStream.Read(buffer, 0, buffer.Length);
  var stringBuffer = Encoding.ASCII.GetString(buffer, 0, bytesRead);
  var messages = 
     stringBuffer.Split(splitString, StringSplitOptions.RemoveEmptyEntries);
  foreach (var message in messages)
  {
    if (MessageReceived != null)
    {
      MessageReceived(this, new SimpleTextClientEventArgs(message));
    }
  }
}

问题是,即使使用了 short.MaxValue 这样大的缓冲区,您实际上也可以填充缓冲区。当您拆分从缓冲区创建的字符串时,最后一个字符串会被压缩,其余的字符串会在下一次读取时出现。

我正在考虑为一行创建一个足够大的缓冲区(根据 RFC2812 是 512 个字符),提取一个子字符串直到第一个“\r\n”,然后将其余数据数组复制到开头缓冲区并使用 offset 参数将更多数据读取到上次迭代未提取的数据的末尾。抱歉,如果这很难理解...

这是最好的解决方案,还是我在这里错过了显而易见的事情?

4

2 回答 2

1

您正在处理 TCP/IP,这意味着您正在处理数据。您不能依赖数据的来源来判断一次调用是否Read会为您提供全部数据。在这种情况下,您可能只想继续阅读(它会阻塞直到有一些数据)并找到将二进制数据转换为文本缓冲区。当您在文本缓冲区中看到行终止符时,您可以通知该消息的更高级别,并将其从缓冲区中删除......但不要假设该消息之后的内容。您可能还有更多数据要读取。

作为旁注,IRC真的只有 ASCII 吗?如果是这样,那至少让事情变得简单一些......

于 2010-08-24T07:40:15.250 回答
0

所以这就是我最终解决它的方法:

var buffer = new byte[Resources.MaxBufferSize];
var contentLength = 0;
while (_tcpClient.Connected)
{
  if (!_networkStream.CanRead || !_networkStream.DataAvailable)
    continue;

  var bytesRead = _networkStream.Read(buffer, contentLength, buffer.Length - contentLength - 1);
  contentLength += bytesRead;
  var message = string.Empty;
  do
  {
    message = ExtractMessage(ref buffer, ref contentLength);
    if (!String.IsNullOrEmpty(message))
    {
      if (MessageReceived != null)
      {
        MessageReceived(this, new SimpleTextClientEventArgs(message));
      }                        
    }
  } while (message != string.Empty);
}

private string ExtractMessage(ref byte[] buffer, ref int length)
{
  var message = string.Empty;
  var stringBuffer = Encoding.UTF8.GetString(buffer, 0, length);
  var lineBreakPosition = stringBuffer.IndexOf(Resources.LineBreak);
  if (lineBreakPosition > -1)
  {
    message = stringBuffer.Substring(0, lineBreakPosition);
    var tempBuffer = new byte[Resources.MaxBufferSize];
    length = length - message.Length - Resources.LineBreak.Length;
    if (length > 0)
    {
      Array.Copy(buffer, lineBreakPosition + Resources.LineBreak.Length, tempBuffer, 0, length);
      buffer = tempBuffer;
    }
  }
  return message;
}
于 2010-08-24T12:54:42.113 回答