2012-04-26 2 views
6

매초 수천 개의 UDP 패킷을 처리해야하는 서버 응용 프로그램 (C#, .NET 4.0)으로 작업 중입니다. 그래서 SocketAsyncEventArg으로 서버를 구현하기로 결정했습니다.UDP 서버의 패킷 수신시 연결 재설정

내가 직면하는 문제는 구현시 단 하나의 패킷 만 수신 한 다음 "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'를 유지하면서 클라이언트와 서버를 다른 컴퓨터에서 실행하면 문제가 해결된다는 것입니다. 당신이 말했듯이, 윈도우 루프백 메커니즘을 가진 무언가가 있어야합니다. – Hemant

+0

네, 저도 놀랄 일이 아닙니다. 한 호스트에서 UDP 소켓을 닫으면 다른 호스트에서 UDP 소켓이 닫히기 때문에 걱정할 것입니다! – Nick