Почему нет обратного вызова от BeginReceive, когда я устанавливаю ReuseAddress в true? UDP
Я создаю сокет 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 ответ
Из того, что я могу сказать, вы должны использовать 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