当我将ReuseAddress设置为true时,为什么没有来自BeginReceive的回调? UDP

时间:2013-09-26 18:57:26

标签: c# sockets asynccallback setsockopt beginreceive

我正在创建一个C#套接字,用于UDP接收和发送功能以及接收的异步回调函数。简单吧!需要一段时间来解决所有的皱纹,但它的工作原理......好吧,只要你养猪港!我需要允许其他应用程序使用相同的端口号。没问题,对吧!有一个选项,SetSocketOption(...)用于ReuseAddress ...

udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);

为什么当我将ReuseAddress设置为true时,回调函数不会再被命中?

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CSharpUtilityLibrary.Utilities;

namespace CSharpNIU.Sockets
{
      public class PacketEventArgs : EventArgs {
      public byte[] Bytes { get; set; }
      public PacketEventArgs(byte[] bytes)
      {
         Bytes = bytes;
      }
   }

   public delegate void PacketEventHandler(object sender, PacketEventArgs e);

   // State object for reading client data asynchronously
   public class StateObject
   {
      // Client  socket.
      public Socket workSocket = null;

      // Size of receive buffer.
      public const int BufferSize = 1553;

      // Receive buffer.
      public byte[] buffer = new byte[BufferSize];
   }

   public class UDPSocket
   {
      // Thread signal.
      public ManualResetEvent allDone = new ManualResetEvent(false);

      public String ApplicationName { get; set; }
      public Form ParentForm { get; set; }
      public Network ApplicationNetwork { get; set; }
      private ConfigGeneric Config { get; set; }
      private Socket udpClient = null;

      public UDPSocket(ConfigGeneric config, String applicationName)
      {
         Config = config;

         ApplicationDetails appDetails = config.GetApplicationByName(applicationName);
         if (appDetails == null)
            return;

         ApplicationNetwork = config.GetNetworkByName(appDetails._network);
         if (ApplicationNetwork == null) return;
      }

      public void StartListening()
      {
         // Data buffer for incoming data.
         byte[] bytes = new Byte[1024];

         IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._networkAddress);
         IPEndPoint localEndPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);

         // Create a UDP Socket
         udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

         // Bind the socket to the local endpoint
         try
         {
            // Set the event to nonsignaled state.
            allDone.Reset();

            // Start an asynchronous socket to listen for connections.
            allDone.Set();
            StateObject stateObject = new StateObject();
            stateObject.workSocket = udpClient;
//------> The line Below causes the begin receive to not call ReadCallback <-------//
            udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
//------> The line Above causes the begin receive to not call ReadCallback <-------//
            udpClient.Bind(localEndPoint);

            udpClient.BeginReceive(stateObject.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), stateObject);

            // Wait until a connection is made before continuing.
            allDone.WaitOne();
         }
         catch (Exception e)
         {
            Console.WriteLine(e.ToString());
         }
      }

      public void ReadCallback(IAsyncResult ar)
      {
         String content = String.Empty;

         // Retrieve the state object and the handler socket from the asynchronous state object.
         StateObject state = (StateObject)ar.AsyncState;
         Socket handler = state.workSocket;

         // Read data from the client socket. 
         int bytesRead = handler.EndReceive(ar);

         if (bytesRead > 0)
         {
            PacketEventArgs packetEventArgs = new PacketEventArgs(state.buffer);
            OnRecevedPacket(packetEventArgs);

            // There  might be more data, so store the data received so far.
            udpClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), state);
         }
      }

      // Event Handlers
      public event PacketEventHandler ReceiveCallback;

      protected virtual void OnRecevedPacket(PacketEventArgs e)
      {
         if (ReceiveCallback != null)
            ReceiveCallback(this, e);
      }

      public void Send(byte[] bytes)
      {
         // Begin sending the data to the remote device.
         IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._broadcastAddress);
         IPEndPoint endPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);

         udpClient.SendTo(bytes, endPoint);
      }
   }
}

1 个答案:

答案 0 :(得分:0)

据我所知,您应该使用UdpClient而不是使用Socket进行低级别。

您还需要使用默认构造函数创建UdpClient,以便能够更改ExclusiveAddressUse等设置。

这家伙有一个工作示例:http://social.msdn.microsoft.com/Forums/en-US/fe830c54-30ab-4ae6-a86a-7c2a9ccd11cf/udpclient-more-than-one-on-the-same-port