代码之家  ›  专栏  ›  技术社区  ›  carlsb3rg

IRC使用NetworkStream-缓冲区填充和行被chomped

  •  1
  • carlsb3rg  · 技术社区  · 15 年前
    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,实际上可以填充缓冲区。当您拆分从缓冲区创建的字符串时,最后一个字符串将被chomped,其余的字符串将伴随下一次读取。

    2 回复  |  直到 15 年前
        1
  •  1
  •   Jon Skeet    15 年前

    你在处理TCP/IP,也就是说你在处理 流动 依赖于数据是如何来的 Read 会不会给你全部的数据。在这样的情况下,您可能只想继续读取(它将阻塞,直到有一些数据)并将二进制数据转换为文本缓冲区。当您在文本缓冲区中看到行终止符时,您可以通知该消息的较高级别,并将其从缓冲区中删除。。。但不要对这个信息后面的内容做任何假设。你可能还有更多的数据要读。

    作为旁注,IRC 真正地 只有ASCII码?如果是这样的话,那至少会让事情简单一点。。。

        2
  •  0
  •   carlsb3rg    15 年前

    我就是这样解决的:

    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;
    }