私は永続的なソケットを持つアプリケーションを持っています (アプリケーションの起動時に開いており、アプリケーションと共に閉じています)。
このソケットは、サーバーがデータをプッシュするために使用されます。
この接続は HTTP または HTTPS のいずれかである可能性があるため、オブジェクトを初期化するために次のコードを記述しました。
s_tcpClient = new TcpClient(s_server.CometIp, s_server.CometPort);
s_tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, false);
s_tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, CST_STREAM_BUFFER_SIZE);
s_tcpClient.ReceiveTimeout = 0;
s_networkStream = s_tcpClient.GetStream();
s_cometStreamReader = null;
if (s_server.Protocol == "HTTPS")
{
SslStream sslStream = new SslStream(
s_tcpClient.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate)
);
sslStream.AuthenticateAsClient(s_server.CometIp);
s_cometStreamReader = new StreamReader(sslStream, Encoding.UTF8, true, CST_STREAM_BUFFER_SIZE);
s_cometStream = sslStream as Stream;
}
else
{
s_cometStreamReader = new StreamReader(s_networkStream, Encoding.UTF8, true, CST_STREAM_BUFFER_SIZE);
s_cometStream = s_networkStream as Stream;
}
このようにして、HTTP プロトコルと HTTPS プロトコルの両方を処理できます。
次に、ソケットでデータが利用可能になるのを待つこのループ (スレッド内) を取得しました。
while (s_networkStream.DataAvailable)
{
numberOfBytesRead = s_cometStream.Read(buffer, 0, buffer.Length);
message.Append(Encoding.UTF8.GetString(buffer, 0, numberOfBytesRead));
ExtractMessages(ref message);
}
ここに私の2つの質問があります:
ドキュメントによると、使用可能なデータがない場合、Read メソッドは 0 を返します。しかし、私の場合、Read は 0 より大きい数値を返すか (一部のデータが読み取られた場合)、タイムアウトになったために例外をスローします...ここで何が欠けていますか? Read が 0 を返すのはどのような状況ですか?
接続が HTTP プロトコルを使用している場合、このコードは正常に機能します。すべてを受信し、メッセージがバッファー サイズ (CST_STREAM_BUFFER_SIZE) よりも大きい場合、DataAvailable は true のままで、ループは残りのデータをすべて読み取ります。しかし、HTTPS でこれを試すと、バッファより小さいメッセージに対してのみ機能します。メッセージが大きい場合、Read メソッドは最初に CST_STREAM_BUFFER_SIZE バイトを読み取り、次に DataAvailable が false になりますが、一部のバイトは明らかに読み取る準備ができています。この場合、別のメッセージを受信すると、DataAvailable が再び true になるため、残りのデータが「スタック解除」されます。私は何を間違っていますか?両方のケースで DataAvailable が同じように動作しないのはなぜですか?
どんな助けでも大歓迎です。