2

1 つのサーバーと多数のクライアント間の通信には、protobuf-net と .NET の TCPClient & NetworkStream を使用します。メッセージの送信には、両側で次の方法を使用します。

   public static bool WriteProtocolBufferToStream(System.IO.Stream stream, object protoBufObject)
    {            
            // ... check parameters ...                
            // ... Determine the 'fieldNumber' of the 'protoBufObject' via a helper dictionary ...  
            if (fieldNumber > -1)
            {
                try { Serializer.NonGeneric.SerializeWithLengthPrefix(stream, protoBufObject, ProtoBuf.PrefixStyle.Base128, fieldNumber); }
                catch (Exception ex)
                {
                    Logger.Instance.Error("Exception: " + ex.Message);
                    return false;
                }
            }
            else
            {
                Logger.Instance.Error("unknown message type");
                return false;
            }
            return true;            
    }

一部のクライアントと少数のメッセージのみの小規模なシナリオでは、すべて問題ありません。しかし、約 40 のクライアントと多くの交換メッセージがあるシナリオでは問題があります。メッセージは非常に小さい (1 ~ 5 個の小さな文字列を含む) ですが、サーバーがこれらのメッセージを複数 (最大 200) 同時に送信する場合があります。

しばらくすると (数分から数時間)、次の例外がスローされます。

ArgumentException: Cannot write to stream. Parameter name: dest

ソースは、protobuf-net のProtoWriterクラス コンストラクターです。destCanWriteのプロパティが falseであるため、この例外がスローされます。私の質問は:しばらくすると true から false に変わるのはなぜですか? バッファのオーバーフローと関係がありますか (同時に多くのメッセージを送信するため)。どうすれば修正できますか?NetworkStream CanWrite

編集:

@[Marc Gravell] がすでに指摘したように、は破棄されるため、true から false にNetworkStream変更されます。CanWriteたとえば、ストリームオブジェクトのWriteTimeoutプロパティにアクセスしようとすると、次のようになります。

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
    at System.Net.Sockets.Socket.GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName)
    at System.Net.Sockets.NetworkStream.get_WriteTimeout()
    at Utilities.CommunicationHelper.WriteProtocolBufferToStream(NetworkStream stream, Object protoBufObject)
    ...

コード内でソケットの破棄を引き起こす可能性のあるものをまだ探しています。ソケットがしばらく (数時間) 後に破棄される原因として他に何が考えられますか?

4

2 に答える 2

0

おそらく、サーバーの TCP/IP ポートを使い果たしていますか?

サーバーが実行しているOSについては言及していませんが、2008年のサーバーであると仮定すると、約16000個の使用可能なポート(49152-65535)があります。接続を閉じると、ポートは再び使用可能になるまで 4 分間 TIME_WAIT ステータスのままになります。これは、4 分以内に 16000 を超える接続がある場合、サーバーが接続を拒否し始めることを意味します。

エラーが発生した場合は、サーバーで次のコマンドを実行してみてください。

netstat -p TCP -ano > netstat.txt

netstat.txt の行数は、確立済みまたは time_wait 状態の TCPv4 接続の数を示しています。

これを調整できます。動的ポートの数を増やすか、time_wait 間隔を減らすか、またはその両方を行います。

実際の値を表示するには:

  • Time_wait (TcpTimedWaitDelay) (デフォルトは 240、または値が見つからない場合は 4 分)

    reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\TcpTimedWaitDelay
    
  • 動的ポート範囲:

    netsh int ipv4 show dynamicportrange tcp
    

役立つリソース:

于 2013-10-18T11:58:06.653 に答える