2012-04-26 37 views
6

Tôi đang làm việc trên ứng dụng máy chủ (C#, .NET 4.0) sẽ cần xử lý hàng nghìn gói UDP mỗi giây. Vì vậy, tôi quyết định SocketAsyncEventArg để triển khai máy chủ.Thiết lập lại kết nối khi nhận gói trong máy chủ UDP

Sự cố mà tôi đang gặp phải là việc triển khai của tôi chỉ nhận được một gói và sau đó tôi nhận được lỗi "ConnectionReset" (tôi không bao giờ tưởng tượng mình có thể gặp lỗi này vì UDP không có kết nối). Đây là triển khai thử nghiệm của tôi:

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(); 
    } 
} 

Xin lỗi vì mã dài nhưng nó thực sự đơn giản. Tôi đợi một gói tin, trả lời đến điểm kết thúc từ xa và sau đó đợi cho đến khi kết thúc. Đây là kết quả đầu ra:

ReceiveNext 

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

Bạn có thể gợi ý điều gì sai trong đoạn mã trên?

Trả lời

10

Điều này xảy ra với ổ cắm UDP. Tất cả những gì bạn cần làm là thay đổi socket operating mode trước khi liên kết nó. Sử dụng mã này theo phương thức Start của bạn.

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

Cảm ơn bạn đã trả lời, bạn có thể cung cấp lời giải thích không? – markmnl

+0

Chỉ cần cách nó là - một số nhà phát triển thiết kế nó như thế và chúng tôi phải làm theo :-) –

1

Nếu bạn xóa hoặc nhận xét cuộc gọi đến Close trên UdpClient thì chương trình sẽ hoạt động như mong đợi. Tại sao điều này xảy ra tôi không chắc chắn, nhưng nó có thể là để làm với mạng loopback Windows.

+0

Có. Bạn đúng rồi. Điều thú vị hơn là nếu chúng ta giữ 'Close' nhưng chạy máy khách và máy chủ trên các máy tính khác nhau, thì vấn đề cũng được giải quyết. Như bạn đã nói, phải có một cái gì đó với cơ chế loopback của Windows. – Hemant

+0

Vâng, tôi không ngạc nhiên vì điều đó. Nếu đóng một ổ cắm UDP trên một máy chủ gây ra việc đóng một ổ cắm UDP trên máy chủ khác, tôi sẽ bắt đầu lo lắng! – Nick

Các vấn đề liên quan