【问题标题】:Why NO Callback from BeginReceive when I set ReuseAddress to true? UDP当我将 ReuseAddress 设置为 true 时,为什么没有来自 BeginReceive 的回调? UDP
【发布时间】:2013-10-02 21:42:40
【问题描述】:

我正在为 UDP 接收和发送功能创建一个 C# 套接字,并为接收提供异步回调函数。很简单,对!消除所有皱纹需要一段时间,但它确实有效......好吧,只要你占领港口!我需要允许其他应用程序使用相同的端口号。没问题,对!有一个选项,SetSocketOption(...) for 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);
      }
   }
}

【问题讨论】:

  • 更新 我刚刚注意到 SetSocketOption 引发了“提供了无效参数”的异常,这会阻止调用 BeginReceive。我还有更多需要调查。
  • 我没有找到任何说明是什么使该行具有无效参数的原因。我确实注意到人们使用 UdpClient 并使用 SocketOptionLevel.Socket 设置套接字选项的一些帖子。这消除了异常,但仍然没有对 ReadCallback 函数的回调。

标签: c# sockets asynccallback setsockopt beginreceive


【解决方案1】:

据我所知,您应该使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 2021-02-11
    相关资源
    最近更新 更多