Detect multiple devices on network using UDP broadcast - C# - c#

I am aware that there a plenty of questions on UDP broadcast for detecting network devices but none of the answers really work for me. I'm guessing that I'm missing something and would be grateful for any help.
I have designed a system which sits on a network and runs a UDP server. Upon receiving a message on some port (AP) it will send a reply back to the sending IP/port.
On the C# side I use the following code:
UdpClient Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("Discover");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
byte[] ServerResponseData = { 0 };
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, AnnouncePort));
ServerResponseData = LanguageUtils.IgnoreErrors(() => Client.Receive(ref ServerEp));
if (ServerResponseData != null)
{
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
deviceList.Add(ServerEp.Address.ToString());
QueryFoundDevices(deviceList);
AvailableDevicesList.Nodes[0].Expand();
}
My issue is that I can only ever detect one of my devices at a time. Ideally, I would like to be able to receive messages from an unlimited number of devices.
I have also tried using async methods, in which case I just receive my own message and don't see any devices. Code example of that:
static void OnUdpData(IAsyncResult result)
{
// this is what had been passed into BeginReceive as the second parameter:
UdpClient socket = result.AsyncState as UdpClient;
// points towards whoever had sent the message:
IPEndPoint source = new IPEndPoint(0, 0);
// get the actual message and fill out the source:
byte[] message = socket.EndReceive(result, ref source);
// do what you'd like with `message` here:
Console.WriteLine("Got " + message.Length + " bytes from " + source);
// schedule the next receive operation once reading is done:
socket.BeginReceive(new AsyncCallback(OnUdpData), socket);
}
Can anyone please advise how I can do this?
Update:
Based on comments - these are Ethernet based devices and I have verified that both devices are replying using Wireshark.

I don't know where is is correct to do this but I have now worked out a way of doing this based upon Lex Li's comment. I thought I would share this just in case anyone else is having a similar issue.
UdpClient Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("Discover");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
byte[] ServerResponseData = { 0 };
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, AnnouncePort));
ServerResponseData = LanguageUtils.IgnoreErrors(() => Client.Receive(ref ServerEp));
string ServerResponse;
while (ServerResponseData != null)
{
ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
deviceList.Add(ServerEp.Address.ToString());
QueryFoundDevices(deviceList);
AvailableDevicesList.Nodes[0].Expand();
ServerResponseData = LanguageUtils.IgnoreErrors(() =>Client.Receive(ref ServerEp))
}
Lex Li pointed out that the first code section I posted in my answer would only receive the first reply. I tried to read the next response and it worked. I am now using the above, which likely needs further optimisation but is working well so far.
Thanks for the help folks!

Related

Sending an UDP broadcast via socket raises exception constantly

All I need to do is sending out a broadcast message with an ASCII encoded command and wait for an answer.
I've found numerous tutorials on how to do this and nearly figured everything out. I studied the MSDN articles about sockets and it's SendTo method but whatever I do or try it raises this exception at my SendTo call:
System.Net.Sockets.SocketException: 'The attempted operation is not supported for the type of object referenced'
The provided error code is 10045. Not very detailed as so often in low level APIs.
I assume it should be correct. I bind to my Ethernet adapter (the one hooked up to the intranet where my device I'm trying to contact resides) on any available port and broadcast to that port I am looking for.
That's my code so far:
byte[] encoded = Encoding.ASCII.GetBytes(cast);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.10.87"), 0));
IPEndPoint broadcastPartner = new IPEndPoint(IPAddress.Broadcast, 32001);
int sent = socket.SendTo(encoded, SocketFlags.Broadcast, broadcastPartner);
Console.WriteLine($"Sent {sent} bytes.");
SpinWait wait = new SpinWait();
while (true)
{
byte[] buffer = new byte[2048];
int read = 0;
try
{
read = socket.Receive(buffer, SocketFlags.Broadcast);
}
catch (Exception)
{
wait.SpinOnce();
continue;
}
if (read == 0) continue;
Console.WriteLine("Received message: " + Encoding.ASCII.GetString(buffer));
}

How to do Network discovery using UDP broadcast

I want to to do network discovery using UDP Broadcast in C#. I don't know how to do this. Can you give me advice on how to do it?
I want to do like this tutorial.
It's very simple to make same thing in C#
Server:
var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");
while (true)
{
var ClientEp = new IPEndPoint(IPAddress.Any, 0);
var ClientRequestData = Server.Receive(ref ClientEp);
var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);
Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
Server.Send(ResponseData, ResponseData.Length, ClientEp);
}
Client:
var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());
Client.Close();
Here is a different solution that is serverless. I had a need to have a bunch of raspberry pis be aware of each other on a network, but had no guarantees of who would be active. So this approach allows everyone to be a client! The complete library is available on GitHub (disclaimer: I created) and that makes this whole process really reaaaally easy for UWP apps.
https://github.com/mattwood2855/WindowsIotDiscovery
This solution assumes that device names are unique and that you want to use JSON strings as the communication protocol, but you could easily just send any other format. Also, in practice try-catch everything ;)
The general mechanism:
Discover your IpAdress
public string IpAddress
{
get
{
var hosts = NetworkInformation.GetHostNames();
foreach (var host in hosts)
{
if (host.Type == HostNameType.Ipv4) return host.DisplayName;
}
return "";
}
}
Set up your listener
var udpPort = "1234";
var socket = new DatagramSocket();
socket.MessageReceived += ReceivedDiscoveryMessage;
await socket.BindServiceNameAsync(udpPort);`
Handle incoming data
async void ReceivedDiscoveryMessage(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs args)
{
// Get the data from the packet
var result = args.GetDataStream();
var resultStream = result.AsStreamForRead();
using (var reader = new StreamReader(resultStream))
{
// Load the raw data into a response object
var potentialRequestString = await reader.ReadToEndAsync();
// Ignore messages from yourself
if (args.RemoteAddress.DisplayName == IpAddress) return;
// Get the message
JObject jRequest = JObject.Parse(potentialRequestString);
// Do stuff with the data
}
}
Send a message
public async void SendDataMessage(string discoveryMessage)
{
// Get an output stream to all IPs on the given port
using (var stream = await socket.GetOutputStreamAsync(new HostName("255.255.255.255"), udpPort))
{
// Get a data writing stream
using (var writer = new DataWriter(stream))
{
// Write the string to the stream
writer.WriteString(discoveryMessage);
// Commit
await writer.StoreAsync();
}
}
}
The idea would be to send a discovery message containing your ip address and name. Then in the receive message function add the ip-name pairs to a List of devices. Add a little logic to avoid duplicates and update Ip address if the ip changes for a given name.
As a bonus, you can have each device send the list of devices they know about. This allows you to minimize udp traffic by not responding when the sender is aware of you. You can even have the receiver compare the list against their own list to discover other devices.
Redundancy is your friend with UDP, there is no guarantee that a packet will be delivered.
I know it's old but someone may still need this...The accepted answer is great but with this little tweak on the server side it's even better.
Fix for the Ilya Suzdalnitski comment (locks up on the second Client.Receive call):
var responseData = Encoding.ASCII.GetBytes("someData");
while (true)
{
var server = new UdpClient(8888);
var clientEp = new IPEndPoint(IPAddress.Any, 0);
var clientRequestData = server.Receive(ref clientEp);
var clientRequest = Encoding.ASCII.GetString(clientRequestData);
Console.WriteLine($"Recived {clientRequest} from {clientEp.Address}, sending
response: {responseData}");
server.Send(responseData, responseData.Length, clientEp);
server.Close();
}
Because after each response the server is closed and recreated, it can work endlessly without locking.
I had the same question but it was not that easy for me as the answer that #rufanov suggests.
Here some situation I had:
Since my application is running normally in a computer that has several network interfaces, I had the problem that the broadcast message was sent only in one of the adapters. To solve this situation I had to get first all the network adapter list and go one by one sending the broadcast message and receiving the answer message.
It is important that you bind the correct localIpEndPoint to your adapters ip address, otherwise you will have problems with the broadcast address by sending.
After some reserch and work I got to this solution. This code corresponds to the server side and will make the network discovery of all devices answering to the braodcast message.
public static void SNCT_SendBroadcast(out List<MyDevice> DevicesList)
{
DevicesList = new List<MyDevice>();
byte[] data = new byte[2]; //broadcast data
data[0] = 0x0A;
data[1] = 0x60;
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, 45000); //braodcast IP address, and corresponding port
NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); //get all network interfaces of the computer
foreach (NetworkInterface adapter in nics)
{
// Only select interfaces that are Ethernet type and support IPv4 (important to minimize waiting time)
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet) { continue; }
if (adapter.Supports(NetworkInterfaceComponent.IPv4) == false) { continue; }
try
{
IPInterfaceProperties adapterProperties = adapter.GetIPProperties();
foreach (var ua in adapterProperties.UnicastAddresses)
{
if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
//SEND BROADCAST IN THE ADAPTER
//1) Set the socket as UDP Client
Socket bcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //broadcast socket
//2) Set socker options
bcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
bcSocket.ReceiveTimeout = 200; //receive timout 200ms
//3) Bind to the current selected adapter
IPEndPoint myLocalEndPoint = new IPEndPoint(ua.Address, 45000);
bcSocket.Bind(myLocalEndPoint);
//4) Send the broadcast data
bcSocket.SendTo(data, ip);
//RECEIVE BROADCAST IN THE ADAPTER
int BUFFER_SIZE_ANSWER = 1024;
byte[] bufferAnswer = new byte[BUFFER_SIZE_ANSWER];
do
{
try
{
bcSocket.Receive(bufferAnswer);
DevicesList.Add(GetMyDevice(bufferAnswer)); //Corresponding functions to get the devices information. Depends on the application.
}
catch { break; }
} while (bcSocket.ReceiveTimeout != 0); //fixed receive timeout for each adapter that supports our broadcast
bcSocket.Close();
}
}
}
catch { }
}
return;
}
For working example, see that project:https://github.com/xmegz/MndpTray
The server periodically sends broadcast messages. The client side receive and process them. Many host information (Os version, IP address, Network interface, etc..) send trought.
udp broadcast cdp lldp

UDP: Read data from all network interfaces

I've the following code to read multicast message coming from the network, for a specified IP+Port
private static void ReceiveMessages(int port, string ip, CancellationToken token)
{
Task.Factory.StartNew(() =>
{
using (var mUdpClientReceiver = new UdpClient())
{
var mReceivingEndPoint = new IPEndPoint(IPAddress.Any, port);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.Bind(mReceivingEndPoint);
mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255);
while (!token.IsCancellationRequested)
{
byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint);
Console.WriteLine("Message received from {0} ",mReceivingEndPoint);
}
}
});
}
I've two network adapter from which I've data coming on this multicast ip+port(confirmed by two instances of wireshark monitoring each network adapter). I see on wireshark a lot of traffic coming on those port+Ip) for both network cards.
The problem is that on my console, I only see messages coming from one network card.
I double checked with netstat, I don't have any other software listening on my port:
So why am I getting traffic from only one of my two network cards?
EDIT:
I even tried the following:
private static void ReceiveMessages(int port, string ip, CancellationToken token, IEnumerable<IPAddress> ipAddresses)
{
foreach (IPAddress ipAddress in ipAddresses)
{
IPAddress ipToUse = ipAddress;
Task.Factory.StartNew(() =>
{
using (var mUdpClientReceiver = new UdpClient())
{
var mReceivingEndPoint = new IPEndPoint(ipToUse, port);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.Bind(mReceivingEndPoint);
mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255);
Console.WriteLine("Starting to listen on "+ipToUse);
while (!token.IsCancellationRequested)
{
byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint);
Console.WriteLine("Message received from {0} on {1}", mReceivingEndPoint,ipToUse);
}
}
});
}
}
I see the "Starting to listen on theCorrectIP" twice(for my two IPs), but it still display only data coming from one network card.
EDIT 2
I did notice something else that is strange too. If I disable the interface on which I receive all data, and then start the software, I now get data from the other interface. If I activate again the interface and restart the software, I still get the traffic on the non-deactivated card.
And I know for sure that I've devices that respond to me, that are connected only to one network(not both)
EDIT 3
Another thing: if I send a message from me(localhost), on all network card that I've, I see them coming on my two network interfaces. BUT, if I start my program twice, only the first programm get messages, not the second one.
Edit 4
Additional info, following the first comment:
I've two ethernet cards, one with the 10.10.24.78 ip, the other with the 10.9.10.234 ip.
It's not me that send data, but network pieces(the port 5353 with this ip is a know multicast address used for mDNS, so I should receive traffic from things like printer, itunes, macs, and some other pieces of software we created). Data are multicasted on the ip
224.0.0.251 and port 5353.
Here is a code that you could use to send data on severals IPs, but like I described, if you start it in local it almost works(except that only one local client receive the message).
private static void SendManuallyOnAllCards(int port, string multicastAddress, IEnumerable<IPAddress> ipAddresses)
{
foreach (IPAddress remoteAddress in ipAddresses)
{
IPAddress ipToUse = remoteAddress;
using (var mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse(multicastAddress)));
mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
var ipep = new IPEndPoint(ipToUse, port);
//IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(multicastAddress), port);
mSendSocket.Bind(ipep);
mSendSocket.Connect(ipep);
byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message");
mSendSocket.Send(bytes, bytes.Length, SocketFlags.None);
}
}
}
EDIT 5
Here is the result of my route print(Didn't know that command), and on my two IPs, I always receive data on the 10.9.10.234
Edit 6
I tried several other things:
Use a socket to receive instead of the UdpClient --> Didn't worked
Set some addition socketOption on the reader(DontRoute =1, Broadcast=1) -->Didn't worked
Specify the MulticastInterface that the reader Socket has to use(using socketOption MulticastInterface) --> Didn't work
I had the same problem that I wanted to receive multicasts from all my network interfaces. As EJP already said, you need to call JoinMulticastGroup(IPAddress multicastAddr, IPAddress localAddress) on the UdpClient for all network interfaces:
int port = 1036;
IPAddress multicastAddress = IPAddress.Parse("239.192.1.12");
client = new UdpClient(new IPEndPoint(IPAddress.Any, port));
// list of UdpClients to send multicasts
List<UdpClient> sendClients = new List<UdpClient>();
// join multicast group on all available network interfaces
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface networkInterface in networkInterfaces)
{
if ((!networkInterface.Supports(NetworkInterfaceComponent.IPv4)) ||
(networkInterface.OperationalStatus != OperationalStatus.Up))
{
continue;
}
IPInterfaceProperties adapterProperties = networkInterface.GetIPProperties();
UnicastIPAddressInformationCollection unicastIPAddresses = adapterProperties.UnicastAddresses;
IPAddress ipAddress = null;
foreach (UnicastIPAddressInformation unicastIPAddress in unicastIPAddresses)
{
if (unicastIPAddress.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
ipAddress = unicastIPAddress.Address;
break;
}
if (ipAddress == null)
{
continue;
}
client.JoinMulticastGroup(multicastAddress, ipAddress);
UdpClient sendClient = new UdpClient(new IPEndPoint(ipAddress, port));
sendClients.Add(sendClient);
}
I am also creating a list of UdpClients so I can send my multicasts on all network interfaces.
I finally found how to do it!
In fact, if I keep exactly the same code, but using it with async methods, it work!!! I just can't understand why it doesn't work with sync method(if someone knows, you're welcome to tell me :) )
Since I've lost 3 days on this, I think it worth an example:
private static void ReceiveAsync(int port, string address, IEnumerable<IPAddress> localAddresses)
{
IPAddress multicastAddress = IPAddress.Parse(address);
foreach (IPAddress localAddress in localAddresses)
{
var udpClient = new UdpClient(AddressFamily.InterNetwork);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(localAddress, port));
udpClient.JoinMulticastGroup(multicastAddress, localAddress);
udpClient.BeginReceive(OnReceiveSink,
new object[]
{
udpClient, new IPEndPoint(localAddress, ((IPEndPoint) udpClient.Client.LocalEndPoint).Port)
});
}
}
And the async method:
private static void OnReceiveSink(IAsyncResult result)
{
IPEndPoint ep = null;
var args = (object[]) result.AsyncState;
var session = (UdpClient) args[0];
var local = (IPEndPoint) args[1];
byte[] buffer = session.EndReceive(result, ref ep);
//Do what you want here with the data of the buffer
Console.WriteLine("Message received from " + ep + " to " + local);
//We make the next call to the begin receive
session.BeginReceive(OnReceiveSink, args);
}
I hope that helps ;)
You need to join the multicast group via all available interfaces. By default, the outgoing IGMP JOIN message will be routed according to the unicast routing tables, which will send it out via the 'cheapest' route, using whichever NIC accesses that route. If your multicast group can be sourced via more than one of those routes, you need to iterate.

UDP Listener using sockets generating type error

Im new to Sockets and C# in general and am having a difficult time implementing a simple upd listener function. I've spent alot of time searching the web tying unsuccessfully to intergate any of the numerious examples online. So any suggestions, links, examples would be greatly appreciated!
At this point, I have a third party application broadcasting over port 6600 a general UPD message containing information about the location of the application server (ServerName, IP Address, etc.). I'd like to design my listener client application to capture the UPD broadcast and generate a collection of the available servers which can be used to future processing.
The problem I'm having is that when I attempt to create the listener using listener.Listen(0) if fails and generates a general type error. If I attempt to us the UdpClient class my application hangs and never returns any data. The Code for both examples is listed below:
namespace UDPListener
{
class Program
{
static void Main(string[] args)
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
listener.Bind(new IPEndPoint(IPAddress.Any, 6600));
listener.Listen(6);
Socket socket = listener.Accept();
Stream netStream = new NetworkStream(socket);
StreamReader reader = new StreamReader(netStream);
string result = reader.ReadToEnd();
Console.WriteLine(result);
socket.Close();
listener.Close();
}
}
}
And the UdpClient:
private void IdentifyServer()
{
//Creates a UdpClient for reading incoming data.
UdpClient receivingUdpClient = new UdpClient(6600);
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
try
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Output.Text = ("This is the message you received " +
returnData.ToString());
Output.Text = ("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
dtb was absolutely write! After much research and some help from a friend I realized that what I was actually looking for was a solution for Multicasting. I'll include the links below.
#dtb, thanks for helping point me in the right direction!
http://www.codeproject.com/Articles/1705/IP-Multicasting-in-C
http://codeidol.com/csharp/csharp-network/IP-Multicasting/Csharp-IP-Multicast-Support/

UDP sometimes can't receive anything

I have a C# application that receives UDP data from a remote host. I find that sometimes my socket receives nothing and I cant seem to find any clues as to why!
Wireshark tells me my data is being sent from the remote device correctly. I cant seem to get why sometimes I can receive fine, and sometimes I can't.
I don't get any exceptions, but OnRecieve never gets called
Here is my code in case it helps:
class cUdpRx
{
private Thread rxThread = null;
private Socket UdpSocket;
private IPEndPoint localEp;
byte[] byData;
//rxbytes event
public delegate void OnRxBytesEventHandler(byte[] rxBuf);
public event OnRxBytesEventHandler OnRxBytesEvent;
/// <summary>
/// Creates the udp socket
/// </summary>
/// <param name="Port"></param>
/// <returns></returns>
public bool CreateSocket(int Port)
{
try
{
byData = new byte[1500]; //create our buffer
UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
localEp = new IPEndPoint(IPAddress.Any,Port);
UdpSocket.Bind(localEp);
UdpSocket.BeginReceive(byData,0,byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
return true; //seemed to work ok
}
catch
{
Dispose();
return false; //something went wrong, abort
}
}
private void OnRecieve(IAsyncResult iar)
{
byte[] rxData;
int nBytesRec = 0;
Socket socket = (Socket)iar.AsyncState;
try //in case something else has already disposed of the socket
{
nBytesRec = socket.EndReceive(iar);
}
catch
{
Debug.WriteLine("cant access udp rx socket");
}
try
{
if (nBytesRec > 0)
{
rxData = new byte[nBytesRec];
Array.Copy(byData, rxData, nBytesRec); //copy exact data into new array
OnRxBytesEvent(rxData);
}
if(!killThreads)
UdpSocket.BeginReceive(byData, 0, byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
}
catch(SocketException se)
{
Debug.WriteLine(se.ToString());
}
}
Any help would be really appreciated as its stopping me from going forward with my project. Thanks
UPDATE
It seems like using IPAdress.any is the problem. If I change:
localEp = new IPEndPoint(IPAddress.Any,Port);
to
localEp = new IPEndPoint(IPAddress.Parse("192.168.0.33"),Port);
where 192.168.0.33 is the IP address of my computer, it receives data every time.
Can anyone explain why?
It is quite useful to use IPAddress.any and receive from both wireless and wired connections.
IPAddress.any is equivalent to 0.0.0.0 and according to MSDN it should receive on all network interfaces.
The usual cause of such problems is not processing packets fast enough. They fill up socket receive buffer and kernel starts dropping them.
Increase socket receive buffer size to accommodate traffic bursts.
Remove everything non-essential from the fast socket reading path.
Consider simple iterative approach bellow instead of working against thread pool:
rxData = new byte[nBytesRec];
while ( !time_to_stop ) {
int len = socket.Receive( rxData );
OnRxBytesEvent( rxData, len );
}
Your code comments mention multicast. Note that you need to add explicit group membership for that, and the fact that you join a multicast group on an interface (either explicitly or as decided via routing table), so if you want to listen for multicast data on two interfaces you need two sockets.
I just got the same problem and resolve it by set timeTolive to big data.
_client = new UdpClient();
_client.Client.Bind(new IPEndPoint(IPAddress.Any, targetURI.Port));
_client.JoinMulticastGroup(IPAddress.Parse(targetURI.Host) , 250);
timeToLive = 250, it works.
timeToLive = 50 , works or not work alternate happened.
timeToLive = none or 0, not work.

Categories

Resources