1

2つのネットワークデバイスの起動順序によっては、一方の端でデータを受信できなくなるように見えるという問題があります。

セットアップは、C#(.NET 4.0)で記述された1つの小さなサーバーであり、TCPを介して通信する、産業用スキャナーからのデータの特定のポートをリッスンします。スキャナーはサーバーアプリケーションに正常に接続し、サーバーが受信して処理するデータの小さなチャンク(シリアル番号)を送信します。ただし、スキャナーで再起動すると(実際には、電源を入れ直しても、接続は正常に閉じられません)、サーバーはデータの処理を停止します。イベントの順序、および問題を引き起こす重要なネットワークトラフィックは、次のようになります。

             SUCCESS                           FAILURE
     |----------------------|             |----------------------|
     |  SCANNER  |  SERVER  |             |  SCANNER  |  SERVER  |
     |----------------------|             |----------------------|
     |           |   Starts |             |  Starts   |          |
     |   Starts  |          |             |           |  Starts  |
     |    Scan   | Received |             |   Scan    | Received |
     |  Restarts |          |             |  Restarts |          |
     --------(Network)-------             --------(Network)-------
     |    SYN    |          |             |    SYN    |          |
     |           | ACK-123  |             |           | SYN ACK  |
     | RST - 123 |          |             |    ACK    |          |
     |    SYN    |          |             |           |          |
     |           |  SYN ACK |             |           |          |
     |    ACK    |          |             |           |          |
     |----------------------|             |----------------------|  
     |    Scan   | Received |             |    Scan   |  !LOST!  |
     |----------------------|             |----------------------|      

ご覧のとおり、SUCCESSシナリオでは、スキャナーの再起動後、サーバーはACKでSYNに応答し、スキャナーは接続が正しいストリームにないことを認識したため、接続をリセットします。サーバーはこれを検出し、適切に処理します。ただし、FAILUREシナリオでは、サーバーはSYN ACK、スキャナーACKで正常に応答し、新しい接続が確立されます。

コードは何も文句を言いませんが、Wiresharkで見られるように、データが受信されてACKされた場合でも、TcpLister/TcpClientはそれ以上データを受信しないようです。どうやらTcpListenerとハンドラーはまだデータの古い接続を待っていますか?私はこのレベルのネットワークプログラミングに慣れていない(そしてC#自体には比較的慣れていない)ので、明らかな何かが欠けているかどうかを間違いなく指摘します。

サーバーのコードスニペット:

public void Run() 
 {
   while (!shutdown)
   {
     shutdown = false; // Reset
     listenerServer = new TcpListener(IPAddress.Any, scanner.Address.Port);

     try
     {
       listenerServer.Start();
       TcpClient handler = listenerServer.AcceptTcpClient();

       while (true)
       {
         try
         {
           incomingData = null;
           dataBuffer = new Byte[256];
           NetworkStream stream = handler.GetStream(); // blocks here
           int i;

           while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
           {
             incomingData += Encoding.ASCII.GetString(dataBuffer, 0, i);
             int startIndex = incomingData.IndexOf(startMarker);
             int endIndex = incomingData.IndexOf(endMarker);
             if (startIndex > -1 && endIndex > -1)
             {
               string serialData = incomingData.Substring(startIndex + 1, endIndex - startIndex - 1);
               scanner.ProcessDataChange(serialData);
             }
           }
         }
         catch (IOException e)
         {
           // Deals with SocketExceptions here...
         }
         finally
         {
           handler.Close();
         }
       }
     }
     catch (SocketException e)
     {
       listenerServer.Stop();
       listenerServer = null;
     }
     finally
     {
       listenerServer.Stop();
       listenerServer = null;
     }
   }
 }
4

2 に答える 2

2

ユーザー@LB(L. B)が質問に回答しましたが、無関係である可能性があると考えて削除しました。実際、それは質問に対する素晴らしい答えだったので、ここに再投稿します。結局、私は作られている新しいつながりを聞いていませんでした。L. Bが彼の回答を再投稿したい場合は、喜んで受け入れます。

L.Bの回答の再投稿

TcpClientハンドラー=listenerServer.AcceptTcpClient();との接続を1つだけ受け入れます。

最初の接続が閉じられると、接続を受け入れなくなります。whileループに移動する必要があります。

編集

これはあなたの質問に対する直接の答えではありません。しかし、私は以下のコードを試しました、そしてそれはうまくいきます。必要に応じて、試すことができます。この回答は後で削除します。

 void Run()
 {
     TcpListener listener = new TcpListener(IPAddress.Any, 12345);
     listener.Start();

    Task.Factory.StartNew(() =>
    {
        while (true)
        {
            var client = listener.AcceptTcpClient();
            Task.Factory.StartNew(() => Handler(client), TaskCreationOptions.LongRunning);
        }
    }, TaskCreationOptions.LongRunning);
 }

 void Handler(TcpClient client)
 {
     using (NetworkStream stream = client.GetStream())
     {
         var dataBuffer = new Byte[256];
         int i;
         while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
         {
             // Processes data here..
             //var s = Encoding.UTF8.GetString(dataBuffer, 0, i);
             //Console.Write(s);

         }
     }
 }
于 2012-11-15T21:28:15.357 に答える
0

このタイプの通常の原因は、tcpの送信境界と受信境界が保持されることを期待していることです。つまり、チャンクを送信し、サーバーで同じチャンクを受信することを期待します。これが発生することは保証されていません。コードを表示しないため、コードに依存しているかどうかはわかりません。

于 2012-11-15T20:01:38.143 に答える