2012-01-16 15 views
1

私はC#でTCPサーバーを作成していますが、奇妙で潜在的にセキュリティ上の問題も発生しています。TelnetブロッキングC#TCPサーバー

  1. A C#のソケットは、着信接続を受け入れるようにAcceptAsync方法を使用して、ポートで待機:次のように新しい接続を受け入れるための

    私の基本的なアーチがあります。

  2. 受け入れを終了するためにThreadPoolを使用して受け入れられた接続をスピンオフします。

すべてがうまく動作しますが、誰かがポートに接続しているとすべてが停止します。

症状:

  • 私は自分のサーバーにtelnetし、サーバが接続を受け入れる終えることは決してありません(すなわち、任意のキーをヒットしていない)任意のデータを送信しない場合。

  • 私のSocketAsyncEventArgs.Completedコールバックは決してテルネット接続でヒットしません。

  • さらに悪いことに、それ以降のすべての接続はブロックされ、キューに入れられ、自分のコードで決して受け入れられません。何かアドバイスをいただければ幸いです

    TCP 127.0.0.1:8221 chance:53960 CLOSE_WAIT

    TCP 127.0.0.1:8221 chance:53962 CLOSE_WAIT

    TCP 127.0.0.1:8221 chance:53964 CLOSE_WAIT

:彼らはCLOSE_WAIT状態に置かれています。

StartAccept:

private void StartAccept(SocketAsyncEventArgs AcceptArgs) 
{ 
    CurrentAcceptArgs = AcceptArgs; 
    AcceptArgs.AcceptSocket = null; 

    if (AcceptArgs.Buffer == null || 
     AcceptArgs.Buffer.Length < 1024) 
    { 
     AcceptArgs.SetBuffer(new byte[1024], 0, 1024); 
    } 

    if (MainSocket != null) 
    { 
     lock (MainSocket) 
     { 
      // If this is false, we have an accept waiting right now, otherwise it will complete aynsc 
      if (MainSocket.AcceptAsync(AcceptArgs) == false) 
      { 
       ThreadPool.QueueUserWorkItem(FinishAccept, AcceptArgs); 
       StartAccept(GetConnection()); 
      } 
     } 
    } 
} 

が接続を受け入れるためのコールバックを完了:

protected override void OnIOCompleted(object sender, SocketAsyncEventArgs e) 
{ 
    PWClientRemote RemoteClient = e.UserToken as PWClientRemote; 

    // Determine which type of operation just completed and call the associated handler. 
    switch (e.LastOperation) 
    { 
     case SocketAsyncOperation.Accept: 
      StartAccept(GetConnection()); 
      ThreadPool.QueueUserWorkItem(FinishAccept, e); 
      break; 
     default: 
      base.OnIOCompleted(sender, e); 
      break; 
    } 
} 

フィニッシュは受け入れ:ここ

private void FinishAccept(object StateObject) 
{ 
    SocketAsyncEventArgs args = (SocketAsyncEventArgs)StateObject; 
    FinishAcceptInternal(args); 
} 

は、Telnet接続からではなく、データを送信する前にwiresharkのです

No.  Time  Source    Destination   Protocol Length Info 
    1 0.000000 192.168.1.146   192.168.1.109   TCP  66  59766 > 8221 [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1 
    2 0.000076 192.168.1.109   192.168.1.146   TCP  66  8221 > 59766 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1 
    3 0.000389 192.168.1.146   192.168.1.109   TCP  60  59766 > 8221 [ACK] Seq=1 Ack=1 Win=65536 Len=0 

これは接続を確立するための完全なハンドシェイクである必要がありますが、Completedイベントは発生しません。

+3

あなたはCLOSE_WAITでグーグル?あなたがした場合、あなたはそれを得た理由を知っています。コードはどこにありますか? – jgauffin

+0

接続試行のタイムアウトを指定できますか? – Fantius

+0

はい、接続が不正なTCP状態になっていることを理解しています。私は解決策を探しています。現在、悪意のあるユーザーが単にtelnetを使用してサーバーに接続することは可能です。 – Stryck

答えて

1

エラーがこの行である:

if (AcceptArgs.Buffer == null || 
    AcceptArgs.Buffer.Length < 1024) 
{ 
    AcceptArgs.SetBuffer(new byte[1024], 0, 1024); 
} 

あなたがバッファを設定した場合、AcceptAsyncはそれまでブロックされますので、これは、いくつかのデータを受信します。 MSDNから

必要な最小バッファサイズは288バイトです。より大きなバッファサイズが指定されている場合、SocketはWinsock AcceptEx呼び出しで受信したアドレスデータ以外のいくつかの余分なデータを期待し、この余分なデータが受信されるまで待機します。

私の修正コード:

// We set a null buffer here. 
// If we set a valid buffer, the accept will expect data 
// and will hang unless it gets it. 
AcceptArgs.SetBuffer(null, 0, 0); 

これは288バイト以下のバッファを設定し、正確に正しい修正であれば、私はわからないが、問題を修正していないようでした。バッファをヌルに設定するだけで、データを送信せずに接続すると、Completedイベントが発生しました。

0

GetConnectionがどこかでブロックされているようです。 通常、サーバーに負荷がかかっていない場合、非同期操作は同期的に完了することがあります。 また、AcceptAsyncがfalseを返すか、コールバックメソッドが呼び出されたということは、非同期操作が完了し、コードが結果を分析する必要があることを意味します。

以下は、非同期に接続を受け入れる単純な非同期TCPサーバースケルトンです。

私は根本的な原因を見つけて、自分の質問に答える
void StartServer() 
{ 
    Socket serverSocket = new Socket(addr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
    serverSocket.Bind(new IPEndPoint(addr, port)); 
    s.Listen(5000); 

    SocketAsyncEventArgs args = new SocketAsyncEventArgs(); 
    args.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptCompleted); 
    args.UserToken = serverSocket; 

    if (!serverSocket.AcceptAsync(args)) 
     AcceptCompleted(this, args); 
} 

void AcceptCompleted(object obj, SocketAsyncEventArgs args) 
{ 
    Socket client = args.AcceptSocket; 
    if (args.SocketError != SocketError.Success) 
     return; 

    StartClientOperations(args.AcceptSocket); 

    args.AcceptSocket = null; 
    Socket s = (Socket)args.UserToken; 
    if (!s.AcceptAsync(args)) 
     AcceptCompleted(this, args); 
} 

void StartClientOperations(Socket newClient) 
{ 
    //start other asynchronous operations here with the client socket 
} 
+0

GetConnection()は、TCP接続が行われる前に発生します。また、単純な接続プールキューへのリンクにすぎません。 – Stryck

+0

GetConnectionは実際のTCP接続が受け入れられた後に呼び出されました。シンプルな接続プールのキューとそのアプリケーションの役割について詳しく説明できますか? –

関連する問題