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 と同じ大きさのバッファーを使用しても、実際にはバッファーをいっぱいにすることができることです。作成した文字列をバッファから分割すると、最後の文字列が切り捨てられ、残りの文字列が次の読み取りに付属します。

1 行 (RFC2812 によると 512 文字) に十分な大きさのバッファーを作成し、最初の "\r\n" まで部分文字列を抽出してから、残りのデータを配列の先頭にコピーすることを考えていました。バッファーを使用し、offset パラメーターを使用して、最後の反復で抽出されなかったデータの末尾にさらにデータを読み取ります。フォローしづらかったらすいません…

それが最善の解決策ですか、それともここで明らかなことを見逃していますか?

4

2 に答える 2

1

TCP/IP を扱っているということは、ストリームデータを扱っているということです。1 回の呼び出しでデータ全体が得られるかどうかという点で、データの取得方法に依存してはなりません。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 に答える