开发者

IRC using NetworkStream - buffer fills and line gets chomped

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,开发者_JAVA技巧 StringSplitOptions.RemoveEmptyEntries);
  foreach (var message in messages)
  {
    if (MessageReceived != null)
    {
      MessageReceived(this, new SimpleTextClientEventArgs(message));
    }
  }
}

Problem is that even with a buffer as big as short.MaxValue, you can actually fill the buffer. When you split the string that you create from the buffer, the last string gets chomped, and the rest of it comes with the next read.

I was thinking of creating a buffer large enough for a single line (which according to RFC2812 is 512 chars), extracting a substring up until the first "\r\n", then array-copying the rest of the data to the beginning of the buffer and using the offset parameter to read more data onto the end of the data that wasn't extracted last iteration. Sorry if that was hard to follow...

Is that the best solution, or am I missing the obvious here?


You're dealing with TCP/IP, which means you're dealing with stream data. You must not rely on how the data comes in terms of whether one call to Read will give you the whole of the data or not. In a case like this, you probably want to just keep reading (it will block until there's some data) and find convert the binary data into a text buffer. When you see a line terminator in the text buffer, you can notify the higher level of that message, and remove it from the buffer... but don't assume anything about what comes after that message. You may well still have more data to read.

As a side-note, is IRC really only ASCII? If so, that at least makes things a bit simpler...


So here's how I ended up solving it:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜