2

次のコードを使用して、非同期 TCP サーバーを作成しています。

private void SetupServerSocket()
{
    var myEndpoint = new IPEndPoint(IPAddress.Any, _port);

    _serverSocket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    _serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
    _serverSocket.Bind(myEndpoint);
    _serverSocket.Listen((int)SocketOptionName.MaxConnections);
}

protected void Open()
{
    SetupServerSocket();
    Opened = true;
    _serverSocket.BeginAccept(AcceptCallback, _serverSocket);
}

private void AcceptCallback(IAsyncResult result)
{
    var connection = new ConnectionInfo();
    try
    {
        // Finish Accept
        var s = (Socket)result.AsyncState;
        connection.Socket = s.EndAccept(result);
        connection.Buffer = new byte[8192];

        lock (_connections)
        {
            _connections.Add(connection);
        }

        // Start Receive and a new Accept
        connection.Socket.BeginReceive(connection.Buffer, 0, connection.Buffer.Length, SocketFlags.None, ReceiveCallback, connection); 
        _serverSocket.BeginAccept(AcceptCallback, result.AsyncState);
    }
    catch (SocketException ex)
    {
        CloseConnection(connection);
    }
    catch (Exception ex)
    {
        CloseConnection(connection);
    }
}

private void CloseConnection(ConnectionInfo ci)
    {
        if (ci.Socket != null)
        {
            if (OnDisconnect != null)
                OnDisconnect.Invoke((IPEndPoint)ci.Socket.RemoteEndPoint);

            ci.Socket.Shutdown(SocketShutdown.Both);
            ci.Socket.Close();
        }

        lock (_connections)
        {
            _connections.Remove(ci);
        }
    }

わかりにくい点がいくつかあります:

1 - _serverSocket.SetSocketOptionTCP での KeepAlive の使用を有効にしました。Windows の既定のキープアライブ タイマーは 2 時間であることがわかりました。この動作は Wireshark を使用して確認されました。

いくつかのグーグル検索の後、http://support.microsoft.com/kb/120642/EN-USで、レジストリにキーを作成することで Windows KeepAliveTime を変更できることがわかりました。このサポート ページの指示が気に入りましたが、KeepAlive タイマーが適用されず (再起動後も)、まだ 2 時間です。Windowsでキープアライブタイマーを変更する方法を知っている人はいますか?

2 - コードconnection.Socket = s.EndAccept(result)は例外をスローできます (通常は SocketException)。なぜSocket.EndResult投げるのSocketExceptionですか?

3 -既に_serverSocketAccept 状態にあるのに、再度 Accept 状態に設定する必要があるのはなぜですか?AcceptCallback()

ありがとうございました

4

1 に答える 1

1
  1. .net Keep Alive タイマーでも同様の問題がありました。byte[1]私はそれを変更する方法を見つけられなかったので、私たちが使用した解決策は、他の実際のデータが送信されていない場合、通常、一定期間後に少量のデータを送信するバックグラウンド ワーカー スレッドを持つことでした。

  2. Socket.EndAccept() は、MSDNに従って予期される例外をスローできます。これらは通常、ソケットが閉じられているなど、ソケットに何かが発生した場合に発生します。これらの例外を正しくキャッチし、プログラムを続行する方法を決定する必要があります。あなたの場合、接続を閉じているようです。

  3. 呼び出し_serverSocket.BeginAccept(AcceptCallback, result.AsyncState);は、最初に受け入れられた接続に対して一度だけコールバックをトリガーします。この後、今後の接続を受け入れるかどうかを決定する必要があります。受け入れる場合は、コールバック内で BeginAccept を再度呼び出します。

于 2013-02-22T11:32:13.503 に答える