2016-10-26 12 views
2

Windows 10でNetCoreを実行しています。私は2つのプログラムを持っています。次のようにNetCoreのC#TcpClient/TcpListenerの奇妙な動作を説明してください

実行順序は次のとおりです。

  • 実行サーバ - クライアント
  • 実行クライアントを処理するためのループがある - クライアントがそのジョブを行い、プロセスが二度目の
  • 実行クライアントを終了します

この配列は、以下のコードを使用してサーバからの次の出力を生成しますクライアントからの出力以下

Waiting for client. 
Reading message. 
Incoming message: This message is longer than what 
Sending message. 
Closing connection. 
Waiting for client. 
Reading message. 
Incoming message: This message is longer than what 
Sending message. 
Closing connection. 
Waiting for client. 

および3210:

Connecting to server. 
Sending message. 
Reading message. 
Incoming message: Thank you! 


Connecting to server. 
Sending message. 
Reading message. 

Unhandled Exception: System.AggregateException: One or more errors occurred. (Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.) ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host 

つまり - クライアントを実行するための第2の試みは例外で終わります。それは奇妙な部分です。

問題を再現するための最小限のサンプルコードです。

Serverコード:

public static async Task StartServerAsync() 
{ 
    TcpListener listener = new TcpListener(IPAddress.Any, 1234); 
    listener.Server.NoDelay = true; 
    listener.Server.LingerState = new LingerOption(true, 0); 
    listener.Start(); 

    while (true) 
    { 
    Console.WriteLine("Waiting for client."); 
    using (TcpClient client = await listener.AcceptTcpClientAsync()) 
    { 
     client.NoDelay = true; 
     client.LingerState = new LingerOption(true, 0); 

     Console.WriteLine("Reading message."); 
     using (NetworkStream stream = client.GetStream()) 
     { 
     byte[] buffer = new byte[32]; 
     int len = await stream.ReadAsync(buffer, 0, buffer.Length); 
     string incomingMessage = Encoding.UTF8.GetString(buffer, 0, len); 
     Console.WriteLine("Incoming message: {0}", incomingMessage); 


     Console.WriteLine("Sending message."); 
     byte[] message = Encoding.UTF8.GetBytes("Thank you!"); 
     await stream.WriteAsync(message, 0, message.Length); 
     Console.WriteLine("Closing connection."); 
     } 
    } 
    } 
} 

クライアントコード:奇妙な

public static async Task StartClientAsync() 
{ 
    using (TcpClient client = new TcpClient()) 
    { 
    client.NoDelay = true; 
    client.LingerState = new LingerOption(true, 0); 

    Console.WriteLine("Connecting to server."); 
    await client.ConnectAsync("127.0.0.1", 1234); 

    Console.WriteLine("Sending message."); 
    using (NetworkStream stream = client.GetStream()) 
    { 
     byte[] buffer = Encoding.UTF8.GetBytes("This message is longer than what the server is willing to read."); 
     await stream.WriteAsync(buffer, 0, buffer.Length); 

     Console.WriteLine("Reading message."); 
     int len = await stream.ReadAsync(buffer, 0, buffer.Length); 
     string message = Encoding.UTF8.GetString(buffer, 0, len); 

     Console.WriteLine("Incoming message: {0}", message); 
    } 
    } 
} 

、我々は

"This message is longer than what the server is willing to read." 

から

"This message is short." 
に、クライアントのメッセージを変更した場合

クライアントの両方のインスタンスがクラッシュすることなく終了し、同じ出力が生成されます。

LingerStateが設定されている3行をすべて省略すると、違いはありません。私はfalseにNODELAYを設定している場合も違いはありません

new LingerState(true, 5)

にLingerStateを設定している場合も動作に違いはありません。言い換えれば、LingerStateとNoDelayの両方の値を設定しても、クラッシュには何の影響も与えないようです。クラッシュを防ぐ唯一の方法は、サーバー側のクライアントからの入力全体を読み取ることです。

これは奇妙なことです。誰かがそれを説明できるかどうかは不思議です。 NetCore 1.0.0およびWindows 10でのみテストされています。

答えて

1

これは最終的に.NET CoreチームのGitHubで回答されました。

長い答え - https://github.com/dotnet/corefx/issues/13114

短い答えの最後のコメントを参照してください -

動作が期待される、とによって設計されています。

-1

私はコードスニペットを取って、実際に実行可能なdemo solutionを依然として未回答の状態で作成しました。

予想される動作を得るためにわずかな変更しか必要ありませんでした。サーバー側のコードでは、実際に文字列全体を読み取る必要があります。ただ、the demo solutionの歴史を見て、あなたはすべての変更が最小限であるが表示されます

StringBuilder sb = new StringBuilder(); 
byte[] buffer = new byte[32]; 
int len; 
do 
{ 
    len = await stream.ReadAsync(buffer, 0, buffer.Length); 
    sb.Append(Encoding.UTF8.GetString(buffer, 0, len)); 
} while (len == buffer.Length); 
Console.WriteLine("Incoming message: {0}", sb.ToString()); 

:で

byte[] buffer = new byte[32]; 
int len = await stream.ReadAsync(buffer, 0, buffer.Length); 
string incomingMessage = Encoding.UTF8.GetString(buffer, 0, len); 
Console.WriteLine("Incoming message: {0}", incomingMessage); 

:次の行を調整します。

+0

申し訳ありませんが、「クラッシュを防止する唯一の方法は、サーバー側のクライアントからの入力全体を読み取ることです」という質問には既に書かれています。質問自体は、メッセージは読み取られません。 – Wapac

関連する問題