一つのC〓〓TCPの非同期プログラムで発生した問題


最近メンテナンス会社の一つであるsocketサービスは主に二つのsocket serverサービスを提供しています。両端に接続されたプログラムに対してデータの透明転送を行います。
プログラム実行中に問題が発生し、プログラムの端がGPRSデバイスであることは周知の通り、GPRSデバイスのネットワーク接続は非常に問題がないため、多くの「奇妙」な問題が発生します。実際のプロセスでは、プログラムが何時間も実行されると、無線端末のsocket serverが切断されてしまい、もう開けられなくなります。長い間探しましたが、見つけられませんでした。
Wirestharkで通信文をキャッチすると、一般的にTCPの三回握手時に発生する問題です。従来のTCPの3回の握手は、TCPの標識から簡単に見ることができます。SYN-SYN ACK-ACKは、実際に問題が発生した場合、SYN-RST ACKとしてマークされます。
サービス側は、クライアントの接続を積極的に拒否するために、リセットの標識を発行していることが明らかになった。
プログラムのserver部分コードは、通常のTCP非同期プログラム方式を採用しています。MSDNコードです。
// This server waits for a connection and then uses asynchronous operations to
        // accept the connection with initial data sent from the client.

        // Establish the local endpoint for the socket.

        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);        // Create a TCP/IP socket.
        Socket listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp );        // Bind the socket to the local endpoint, and listen for incoming connections.
        listener.Bind(localEndPoint);
        listener.Listen(100);        while (true) 
        {            // Set the event to nonsignaled state.
            allDone.Reset();            // Start an asynchronous socket to listen for connections and receive data from the client.
            Console.WriteLine("Waiting for a connection...");            // Accept the connection and receive the first 10 bytes of data. 
            // BeginAccept() creates the accepted socket.
            int receivedDataSize = 10;
            listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener);            // Wait until a connection is made and processed before continuing.
            allDone.WaitOne();
        }
    }    public static void AcceptReceiveDataCallback(IAsyncResult ar) 
    {        // Get the socket that handles the client request.
        Socket listener = (Socket) ar.AsyncState;        // End the operation and display the received data on the console.
        byte[] Buffer;        int bytesTransferred;
        Socket handler = listener.EndAccept(out Buffer, out bytesTransferred, ar);        //      ,      socket   
        listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener);
    }
問題の位置付けを経て、プログラムの非同期受信エコーに問題があったと判断できますが、実際にデバッグ情報を追加したところ、プログラムのポートが開けられなくなりました。再度、コールバック関数の操作を行います。打つ情報はありません。TCP非同期プログラミングは、一般的にペアの出現BeginnXXX...endXXXであり、再度コールバック関数によって具体的な処理を行う。
acceptのコールバック関数として、コードの中でtry.ccachを使って異常を捕捉します。実際の問題はここにあるかもしれません。コードは以下の通りです。
 public static void AcceptReceiveDataCallback(IAsyncResult ar) 
    {        // Get the socket that handles the client request.
        Socket listener = (Socket) ar.AsyncState;        // End the operation and display the received data on the console.
        byte[] Buffer;        int bytesTransferred;        try{
            Socket handler = listener.EndAccept(out Buffer, out bytesTransferred, ar);
        }        catch(  1 e){
            ...            return;
        }        catch(  2 e){
            ...            return;
        }        //      ,      socket   
        listener.BeginAccept(null, receivedDataSize, new AsyncCallback(AcceptReceiveDataCallback), listener);
    }
プログラムは実際にポートが開けられなくなる前に「異常1」/「異常2」に入ったことがあり、プログラムがリセットされた可能性が高いと判断し、再配達ができない。この時、すべてのポートが開いて操作すると、sockett.listenの列に入ります。accpetの列の内容はbegin.end操作では取り出せません。列がいっぱいになったら、socketの底のプロトコルスタックは新しいsocketの接続を拒否します。