Receiving udp packet on designated network card c# - c#

I have 3 different network cards each with their individual responsibility. Two of the cards are receiving packets from a similar device (plugged directly into each individual network card) which sends data on the same port. I need to save the packets knowing which device they came from.
Given that I am required to not specify the ip address of the devices sending me the packets, how can I listen on a given network card? I am allowed to specify a static ip address for all 3 nics if needed.
Example: nic1 = 169.254.0.27, nic2 = 169.254.0.28, nic3 = 169.254.0.29
Right now I have this receiving the data from nic1 and nic2 without knowing which device it came from.
var myClient = new UdpClient(2000) //Port is random example
var endPoint = new IPEndPoint(IPAddress.Any, 0):
while (!finished)
{
byte[] receivedBytes = myClient.Receive(ref endPoint);
doStuff(receivedBytes);
}
I can't seem to specify the static ip address of the network cards in a manner which will allow me to capture the packets from just one of the devices. How can I separate these packets with only the knowledge that they are coming in on two different network cards?
Thank you.

You're not telling the UdpClient what IP endpoint to listen on. Even if you were to replace IPAddress.Any with the endpoint of your network card, you'd still have the same problem.
If you want to tell the UdpClient to receive packets on a specific network card, you have to specify the IP address of that card in the constructor. Like so:
var listenEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.2"), 2000);
var myClient = new UdpClient(listenEndpoint);
Now, you may ask "What's the ref endPoint part for when I'm calling myClient.Receive(ref endPoint)?" That endpoint is the IP endpoint of the client. I would suggest replacing your code with something like this:
IPEndpoint clientEndpoint = null;
while (!finished)
{
var receivedBytes = myClient.Receive(ref clientEndpoint);
// clientEndpoint is no longer null - it is now populated
// with the IP address of the client that just sent you data
}
So now you have two endpoints:
listenEndpoint, passed in through the constructor, specifying the address of the network card you want to listen on.
clientEndpoint, passed in as a ref parameter to Receive(), which will be populated with the client's IP address so you know who is talking to you.

Check this out this:
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
Console.WriteLine("Name: " + netInterface.Name);
Console.WriteLine("Description: " + netInterface.Description);
Console.WriteLine("Addresses: ");
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
Console.WriteLine(" " + addr.Address.ToString());
}
Console.WriteLine("");
}
Then you can choose on which address start listening.

look, if you create your IPEndPoint in the following way it must work:
IPHostEntry hostEntry = null;
// Get host related information.
hostEntry = Dns.GetHostEntry(server);
foreach(IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, port);
...
try to do not pass 0 as port but a valid port number, if you run this code and break the foreach after the first iteration you will have created only 1 IPEndPoint and you can use that one in your call to: myClient.Receive
notice that the UdpClient class has a member calledd Client which is a socket, try to explore the properties of that object as well to find out some details, I have found the code I gave you here: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx

Related

How to connect windows and android device over internet programmatically on Non-Local network

I want to connect android with windows so that i can send my custom data.
so far i have only seen localhost examples.
but i want to connect my android which is on Sim-internet with windows connected through Ethernet.
this is android's code so far(client)
socket = Socket(address, port)
outputStream = socket.getOutputStream()
outputStream.write(data)
and this is C# windows(server)
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("localhost");//localServer
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 10090);
Console.WriteLine("initiating " + ipEndPoint.Port + ", " + ipAddress.ToString());
using Socket listener = new(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
var handler = await listener.AcceptAsync();
while (true)
{
// Receive message.
var buffer = new byte[1_024];
var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
Console.WriteLine(
$"Socket server received message: \"{response.Replace(eom, "")}\"");
break;
}
}
as you can see it is localhost which can only be accessed by localNetworked devices
but i want to connect it over internet from different networked devices
How can i implement that .?
Your socket should bind to all addresses, not the local (new IPEndPoint(IPAddress.Any, ...)).
Your server is most likely behind a firewall/NAT so you need to setup port forwarding so your server can be accessed from the internet.
If the servers public IP address is static then you can use that. Otherwise you have to purchase a domain and configure a DNS server or use a free dynamic DNS service like No-IP or FreeDNS...

Sending broadcast packet issue

I am currently working on a C#/Android client/server project.
I have a server application, running C# on Windows, which sends a broadcast message on port 8000.
The idea is the client application (Android) receives the broadcast and then shows the server hostname and IP, from the message sent via the broadcast, on the Android device for the user to select.
Below is how I am attempting to do the broadcast.
int availableTCPSocket = 0;
try
{
//UdpClient udp = new UdpClient();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
availableTCPSocket = getAvailableTCPSocket();
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, BROADCAST_PORT);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.255"), BROADCAST_PORT);
XmlGenerator xmlGenerator = new XmlGenerator();
xmlGenerator.addStartElement("ServerInformation");
xmlGenerator.addElementString("Hostname", Dns.GetHostName());
NetworkAdapterDetails networkAdapterDetails = getNetworkAdapterDetails();
xmlGenerator.addElementString("IP_Address", networkAdapterDetails.ipAddress);
xmlGenerator.addElementString("MAC_Address", networkAdapterDetails.macAddress);
xmlGenerator.addElementString("AvailableTCPSocket", availableTCPSocket.ToString());
xmlGenerator.addEndElement();
xmlGenerator.flushAndCloseXmlWriter();
string udpData = xmlGenerator.returnXml();
byte[] sendBytes = Encoding.ASCII.GetBytes(udpData);
while (true)
{
//udp.Send(sendBytes, sendBytes.Length, endpoint);
socket.SendTo(sendBytes, endpoint);
Console.WriteLine("Broadcast Sent");
System.Threading.Thread.Sleep(5000);
}
}
catch (Exception ex)
{
Console.WriteLine("Broadcast Sender Exception: {0}", ex.Message);
}
If I set the endpoint to be IPAddress.Broadcast it says it is 255.255.255.255 but my devices never receive the broadcast.
If I change the endpoint to be hardcoded to 192.168.1.255 then my devices receive the broadcast.
So because of this I have two questions.
If I use IPAddress.Broadcast why don't my devices receive anything if this is supposed to be broadcast.
If 192.168.1.255 is the correct broadcast address, how can I find out what the addresss should be dynamically, the idea is the server will be provided for download so has to work on different network configurations where 192.168.1.255 might not be the correct address.
It also takes a long time for the device to receive the packet, the server writes to the console each time its looped round and sends the broadcast but it takes about 4 or 5 broadcasts to be sent before the devices receives it. Its on a WIFI network but strong signal on all devices, 60mb download on the internet and 2ms ping between router and devices.
Thanks for any help you can provide.
Windows 7 handles 255.255.255.255 broadcast in a different way. More info here: Send UDP broadcast on Windows 7
use subnet broadcast instead of 255.255.255.255
Code to Get subnet broadcast address
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
You need to enable sending broadcast messages on the socket with socket.EnableBroadcast = true. Then you should be able to send them to 255.255.255.255 just fine.
Reference: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.enablebroadcast(v=vs.110).aspx
Over wi-fi sometimes doesn't allow the packets send over 255.255.255.255 depending on the security settings in it. Find the broadcast address of the network at run time & use it. You can get the broadcast network address of any network by performing the below operation.
broadcastaddress = (ipaddressofthesystem & netmask) & ~netmask;
Also as an alternative you should consider using multicast address.

How to detect destination IP address from UDP packets using UDPClient Class

I am working on the application which send and receive messages on UDP between client app and server app.
On my server I have 4 different network cards, e.g. nic1 = 169.524.15.12, nic2 = 169.524.15.65, etc. My DNS is point to nic2. The client app resolves the DNS and send data to nic2. However my server app sometime respond to client from nic1.
I'm using an UdpClient to listen for incoming packets.
This is my server application code:
objSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint objEndPointOfServer = new IPEndPoint(IPAddress.Any, 5000);
objSocketServer.Bind(objEndPointOfServer);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, BUFSIZE - 1, SocketFlags.None, ref objEndPointOfServer, DoReceiveFromClient, objSocketServer);
private void DoReceiveFromClient(IAsyncResult objIAsyncResult)
{
try
{
// Get the received message.
_objSocketReceivedClient = (Socket)objIAsyncResult.AsyncState;
EndPoint objEndPointReceivedClient = new IPEndPoint(IPAddress.Any, 0);
// Received data.
int intMsgLen = _objSocketReceivedClient.EndReceiveFrom(objIAsyncResult, ref objEndPointReceivedClient);
byte[] arrReceivedMsg = new byte[intMsgLen];
Array.Copy(_arrReceivedDataBuffer, arrReceivedMsg, intMsgLen);
// Client port.
// Get and store port allocated to server1 while making request from client to server.
int _intClientServer1Port = ((IPEndPoint)objEndPointReceivedClient).Port;
// Send external ip and external port back to client.
String strMessage = ((IPEndPoint)objEndPointReceivedClient).Address.ToString() + ":" + _intClientServer1Port.ToString();
byte[] arrData = Encoding.ASCII.GetBytes(strMessage);
objSocketServer.SendTo(arrData, arrData.Length, SocketFlags.None, objEndPointReceivedClient);
// Start listening for a new message.
EndPoint objEndPointNewReceivedClient = new IPEndPoint(IPAddress.Any, 0);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, _arrReceivedDataBuffer.Length, SocketFlags.None, ref objEndPointNewReceivedClient, DoReceiveFromClient, objSocketServer)
}
catch (SocketException sx)
{
objSocketServer.Shutdown(SocketShutdown.Both);
objSocketServer.Close();
}
}
}
Is there any way so that in code, I can detect that I have received packet on which IP address on server and revert with the response with same IP?
Arguably, I could resolve DNS in server app as well and make sure that my server app only listen to IP on which client app is sending packets, however that approach will not work for me when my server app have to listen on > 1 IP.
The SendTo command will use the appropriate NIC (aka, local interface) for the destination address provided. The system metrics determine that. It's not something you set in your code. To view the system metrics, run the command netstat -rn and look at the Interface column. You many need to adjust those if you have a tie. You can enumerate them in code as well using GetAllNetworkInterfaces() and bind to a specific one (if that is what you wanted).

UDP multicasting with multiple NICs only works when one interface is active

I have looked all over and cannot find a solution to this problem. I have tried every combination I could see with no luck.
Basically, I would like to choose an interface, start a UDP client on two machines and Send/Receive messages. Everything works fine when only one NIC is active, but when two are active, it stops working. I have looked with Wireshark and with one NIC can see packets coming in and going out.
Now when I use two NICs, I can only TX from the first enumerated one and cannot receive on either. WireShark does not show any received packets on the port for either of the two NICs when they are both active.
The code is the following. I used to just have one socket but was trying some different things.
public UDPInstance(IPAddress ip, int port, int RXFrequency)
{
rxFreq = RXFrequency;
// Listener Init
TXclient = new UdpClient();
RXclient = new UdpClient();
TXclient.ExclusiveAddressUse = false;
RXclient.ExclusiveAddressUse = false;
//localEp = new IPEndPoint(ip, port);
TXlocalEp = new IPEndPoint(ip, port);
RXlocalEp = new IPEndPoint(IPAddress.Any, port);
TXclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
RXclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
TXclient.Client.Bind(TXlocalEp);
RXclient.Client.Bind(RXlocalEp);
InterfaceIP = ip.ToString();
multicastaddress = IPAddress.Parse("239.0.0.222");
TXclient.JoinMulticastGroup(multicastaddress);
RXclient.JoinMulticastGroup(multicastaddress);
// Sender Init
remoteep = new IPEndPoint(multicastaddress, port);
Listener = null;
RXData = new List<string>();
StartListenerThread();
}
public void StartListenerThread()
{
Listener = new Thread(new ThreadStart(ListenerThread));
Listener.IsBackground = true;
Listener.Start();
}
public void StopListenerThread()
{
Listener.Abort();
}
private void ListenerThread()
{
while (true)
{
Byte[] data = RXclient.Receive(ref remoteep);
string datastr = Encoding.Unicode.GetString(data);
if (datastr != "")
{
string[] PacketStrings = datastr.Split(new char[] { '~' });
foreach (string pkt in PacketStrings)
RXData.Add(pkt);
}
Thread.Sleep(rxFreq);
}
}
public void Transmit(string data)
{
byte[] buffer;
buffer = Encoding.Unicode.GetBytes(data);
TXclient.Send(buffer, buffer.Length, remoteep);
}
Mike G is correct. One of the constructors for the UDPClient class takes an IPEndPoint as an argument. If the IPEndPoint is set to the IP address of a local interface, then that is the interface that the UDPClient and underlying socket will use so yes, you can have two UDP clients bound to the same port on a a machine as long as they are on seperate local IP interfaces (i.e. multi-homed or multi-NIC).
I know this thread is old, but having the same problem, I thought I would contribute anyway.
On my 'sender' machine, I have 6 NICs. But only 1 needs to be able to send multicast messages, so I used this trick from http://sinclairmediatech.com/using-multicast-on-windows-with-multiple-nics/ :
A little trick I use to make sure I am getting the multicast on the
right interface.
Open cmd as administrator (right click run as administrator)
Delete the default multicast routes. > route delete 224.0.0.0 mask 240.0.0.0
Add the route to the NIC you want. > route add 224.0.0.0 mask 240.0.0.0 IP_of_NIC
I had the same issue on a windows failover cluster...
Multiple nics....
I ended up opening a case with Micorsoft as I thought it was an OS issue.
It wasn't.
You need to specify the IP of the interface you whant to use to create a IPEndpoint.
THen use that endpoint when creating the socket instead of IPAddress.any
That solved the problem for me.
Hope it helps even if it is late.

Receiving broadcast messages

I'm trying to receive broadcast messages using C# code in an ISDN network with BRI interface at my end.
I see the packets sent to the broadcast ip address (239.255.255.255) on some ports using Comm View tool.
But when I try to listen to this IP address, it says the address is not in a valid context.
But when I send broadcast messages to 255.255.255.255 on a port, I can receive those messages with the below code..
What could be the problem with this ip address - 239.255.255.255 ?
The code I use to listen to broadcast messages is..
UdpClient udp = new UdpClient();
IPEndPoint receiveEndPoint = new IPEndPoint(IPAddress.Any, 8013);
// If I use IPAddress.Parse("239.255.255.255") to listen to,
// it says "the address is not in a valid // context."
udp.Client.Bind(receiveEndPoint);
udp.BeginReceive(_Callback, udp);
static private void _Callback(IAsyncResult iar)
{
try
{
UdpClient client = (UdpClient)iar.AsyncState;
client.BeginReceive(_Callback, client);
IPEndPoint ipRemote = new IPEndPoint(IPAddress.Any, 8013);
byte[] rgb = client.EndReceive(iar, ref ipRemote);
Console.WriteLine("Received {0} bytes: \"{1}\"",
rgb.Length.ToString(), Encoding.UTF8.GetString(rgb));
}
catch (ObjectDisposedException)
{
Console.WriteLine("closing listening socket");
}
catch (Exception exc)
{
Console.WriteLine("Listening socket error: \"" +
exc.Message + "\"");
}
}
There are packets sent to the broadcast ipaddress (239.255.255.255) which I can see in Commview tool, but can't receive them from the code...
Can anybody help me out please?
Thanking you in advance,
Prasad Kancharla.
I haven't done much with multicasting, but I believe that preparing to receive multicast packets is a two-step process. First, you bind to a local IP address, which is what you've done with IPAddress.Any. Then, you need to specify which multicast group you wish to join using a MulticastOption object with the Socket.SetSocketOption method.
The MSDN Library has an example for your reference.
It sounds like you're assuming that the address is a directed broadcast (subnet-local broadcast) when it's actually in the IP address range reserved for multicasting, which is something else entirely.

Categories