2012-04-26 39 views
6

毎秒何千ものUDPパケットを処理する必要のあるサーバーアプリケーション(C#、.NET 4.0)を作成しています。だから私はSocketAsyncEventArgにサーバーを実装することにしました。UDPサーバーでパケットを受信すると接続がリセットされる

私が直面している問題は、実装がただ1つのパケットを受信して​​から、「ConnectionReset」エラーが発生するということです(UDPがコネクションレスであるためこのエラーが発生するとは想像もしません)。ここにテスト実装があります:

using System; 
using System.Net; 
using System.Net.Sockets; 

static class Program 
{ 
    static void Main(string[] args) 
    { 
     UdpEchoServer.Start(); 

     while (true) 
     { 
      Console.ReadLine(); 
      SendPacket(); 
     } 
    } 

    static void SendPacket() 
    { 
     Console.WriteLine("SendPacket"); 
     var c = new UdpClient(); 
     c.Send(new byte[5], 5, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 445)); 
     c.Close(); 
    } 
} 

static class UdpEchoServer 
{ 
    static Socket mSocket; 
    static byte[] mBuffer; 
    static SocketAsyncEventArgs mRxArgs, mTxArgs; 
    static IPEndPoint mAnyEndPoint, mLocalEndPoint; 

    public static void Start() 
    { 
     mAnyEndPoint = new IPEndPoint(IPAddress.Any, 0); 
     mLocalEndPoint = new IPEndPoint(IPAddress.Any, 445); 

     mBuffer = new byte[1024]; 

     mRxArgs = new SocketAsyncEventArgs(); 
     mTxArgs = new SocketAsyncEventArgs(); 

     mRxArgs.Completed += ReceiveComplete; 
     mTxArgs.Completed += SendComplete; 

     mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
     mSocket.Bind(mLocalEndPoint); 
     ReceiveNext(); 
    } 

    static void ReceiveNext() 
    { 
     Console.WriteLine("ReceiveNext"); 

     mRxArgs.RemoteEndPoint = mAnyEndPoint; 
     mRxArgs.SetBuffer(mBuffer, 0, mBuffer.Length); 

     if (!mSocket.ReceiveFromAsync(mRxArgs)) 
      Console.WriteLine("Error in ReceiveNext: " + mRxArgs.SocketError); 
    } 

    static void ReceiveComplete(object sender, SocketAsyncEventArgs e) 
    { 
     Console.WriteLine("Receive Complete: " + mRxArgs.SocketError); 

     if (mRxArgs.SocketError != SocketError.Success) 
      return; 

     mTxArgs.SetBuffer(mBuffer, 0, mRxArgs.BytesTransferred); 
     mTxArgs.RemoteEndPoint = mRxArgs.RemoteEndPoint; 

     Console.WriteLine("Sending reply packet"); 

     if (!mSocket.SendToAsync(mTxArgs)) 
      Console.WriteLine("Error in ReceiveComplete: " + mRxArgs.SocketError); 
    } 

    static void SendComplete(object sender, SocketAsyncEventArgs e) 
    { 
     Console.WriteLine("Send Complete: " + mTxArgs.SocketError); 

     if (mTxArgs.SocketError != SocketError.Success) 
      return; 

     ReceiveNext(); 
    } 
} 

申し訳ありませんが、長いコードですが、実際には簡単です。私は、パケットを待って、リモートエンドポイントに返信し、次のものを待つ。ここに出力があります:

ReceiveNext 

SendPacket 
Receive Complete: Success 
Sending reply packet 
Send Complete: Success 
ReceiveNext 
Error in ReceiveNext: ConnectionReset 

上記のコードスニペットで何が間違っているとお考えですか?

答えて

10

これはUDPソケットで発生します。バインドする前にsocket operating modeを変更するだけです。 Startメソッドでこのコードを使用してください。

mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

const int SIO_UDP_CONNRESET = -1744830452; 
byte[] inValue = new byte[] {0}; 
byte[] outValue = new byte[] {0}; 
mSocket.IOControl(SIO_UDP_CONNRESET, inValue, outValue); 

mSocket.Bind(mLocalEndPoint); 
+0

答えをありがとう、あなたは説明をお願いしますか? – markmnl

+0

ちょうどそれはある方法 - それのようないくつかの開発者はそれを設計し、私たちに従う必要があります:-) –

1

Closeへのコールを削除またはコメントアウトすると、UdpClientにプログラムが正常に動作します。なぜこれが起こっているのか分かりませんが、Windowsのループバックネットワーキングと関係があります。

+0

はい。あなたが正しいです。もっと興味深いのは、 'Close'を保ちながらクライアントとサーバを別々のコンピュータで動かすと、問題も解決されるということです。あなたが言ったように、Windowsのループバック機構を備えた何かがなければなりません。 – Hemant

+0

はい、私はそれに驚いていません。あるホスト上でUDPソケットを閉じると、別のホスト上のUDPソケットが閉じてしまった場合は、心配してしまいます。 – Nick

関連する問題