Sending and receiving UDP packets in .NET - c#

I am trying to test UDP communications on a LAN. I have a small piece of code to and I have tried to run it in 2 computers (one should wait to receive and the other one should send). The strange thing is that computer A sends and B receives properly but if I try A to receive and B to send it does not work. Do you know why could it be?
public void SendBroadcast(int port, string message)
{
UdpClient client = new UdpClient();
byte[] packet = Encoding.ASCII.GetBytes(message);
try
{
client.Send(packet, packet.Length, IPAddress.Broadcast.ToString(), port);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void Receive(int port)
{
UdpClient client = null;
try
{
client = new UdpClient(port);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
IPEndPoint server = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
try
{
byte[] packet = client.Receive(ref server);
Console.WriteLine("{0}, {1}", server, Encoding.ASCII.GetString(packet));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
And the calls:
SendBroadcast(444, "hello"); Receive(444);
If I run 2 instances of the program on the same computer it works properly but creates 3 packages per call.
Thanks in advance.

Try using the async methods so that you can keep listening for messages without blocking to send messages.

Well, if the same code works on one and not the other, it's your environment. Check your firewall settings, make sure it's not preventing the broadcast on the sender or preventing receipt on the receiver. Wireshark (or even Windows' netmon) should be helpful here.

What networking gear is inbetween these two systems?
Are the two systems on the same subnet with the same subnetmask?
There's a funny thing with IPV4 networks; you can have multiple broadcast addresses. You can broadcast to the local network or to the local subnet. These are distinctly different addresses, and if one system's IP setup is different it may not realize that it should listen for this local subnet broadcast.
Things to try:
Ensure IPV6 is disabled on both ends (IPV6 doesn't support broadcast address, but lets just establish a baseline).
Explictly set the IP address in the program, does it work? My guess will be yes, so we have to determine why.
Load up wireshark and sniff the packets. See if they are making it all the way to the remote host, and he is just ignoring them.

When trying to do this asynchronously, Microsoft neglects to tell users to create their own partial class like this (see below). Very simple, but without this, it can be difficult to read through their examples.
private partial class UdpState
{
public UdpClient u;
public IPEndPoint e;
}

Related

Handling IP change on server side TCPListener Socket

I am using TcpListener class to create a TCP socket on a certain IP and port in my machine. The code I use is as follows :
tcpListener = new TcpListener("192.168.0.110", 8005);
try
{
tcpListener.Start();
}
catch (Exception e)
{
Console.WriteLine(e);
return;
}
This works fine. I want to use a check thread to check the status of the listener.
private void CheckConnections()
{
while (true)
{
if (_tcpListener.Server.IsBound)
{
Console.WriteLine(_tcpListener.Active);
Console.WriteLine("IsBound : True");
}
else
{
Console.WriteLine(_tcpListener.Active);
Console.WriteLine("IsBound : False");
}
Thread.Sleep(2000);
}
}
When I change the IP of my machine manually from adapter settings, for example from "192.168.0.110" to "192.168.0.105", in the "netstat -ano" command I still see that the " 192.168.0.110:8005" is in Listening state. Also I could not find a way to subscribe to this change from my code. So my question is how to handle IP change on server side socket? Is there a way that I can get IP change information from the socket itself?
Sockets remain in listening state for a while after being closed. This is deliberate and is due to the way sockets have been designed. it doesn't mean your code is still listening, it means the O/S is listening and it will eventually go away.
As for the second part of the question, you can listen to the NotifyAddrChange notification, close your socket, and reopen on the new address.
Here is an article on how to do it.
https://www.codeproject.com/Articles/35137/How-to-use-NotifyAddrChange-in-C
I'm not sure if this is what you want.
Try to use TcpListener(IPAddress.Any, 8005);
This will accept any IPAddress so you don't have to change it on code everytime.
Unless you want to change it while the program is running, that will be a little bit more complicated. You would have to close the socket and change the IP.

How to get public port number of TcpListener?

I'm trying directly connect (using TCP) two devices that are behind routers implementing NAT. As I see, routers are translating port number of my devices, so port 13000 (port where my app is listening for incoming TCP connections) on my computer will have completly different value as seen publicly. In order to connect two devices, I need to know what the listener's "public port number" is.
I've created "rendezvous server" which is available publicly. Firstly, I've created TCP connection between client A and server. Server extracted port number and passed it to other clients so they could try to connect to client A. But I realized, that when I create new Tcp connection with server, my app creates new port from which it sends packets. So server extracts public port of newly created port used just for connection to that server and not public port of my listener.
So I'm trying to solve it other way. The idea is: I'm sending UDP packets with source port set to port of TcpListener. This way, theoretically, server could extract from incoming message public port of TcpListener (by getting source port from UDP datagram) and pass it to other devices in my network.
// client side
public void AdvertiseListener(IPAddress address, int port, Guid localDeviceId)
{
UdpClient client = new UdpClient(ListenerPort); // changing datagram source to port of my TcpListener
IPEndPoint remoteEP = new IPEndPoint(address, port);
_logger.LogInformation($"Advertising Tcp port to server at {address.MapToIPv4().ToString()}:{port}");
byte[] data = localDeviceId.ToByteArray();
for (int a = 0; a < 10; a++)
{
client.Send(data, data.Length, remoteEP);
}
}
// server side
public void AdvertisementsHandler()
{
AdvertisementListener = new UdpClient(ListenerPort);
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
private void HandleAdverticement(IAsyncResult ar)
{
IPEndPoint senderIpEndPoint = new IPEndPoint(0, 0); // source address of incoming datagram
var receivedData = AdvertisementListener.EndReceive(ar, ref senderIpEndPoint);
[...]
_logger.LogInformation($"ADVERTICEMENT RECEIVED, port is {senderIpEndPoint.Port}");
try
{
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
catch (Exception e)
{
_logger.LogError("Advertiser failed");
}
}
The problem is: my server receives not translated number for some reason. senderIpEndPoint in HandleAdverticement equals 13000 which is my private port number. It seems like my router, ironically, leaves port as it is this time. Do you have any ideas of what can I change to solve my problem?
Your TcpListener doesn't have a public port number. If a router is using NAT to change your source port number along the way, your application will not know about it. This is why port-forwarding is required when you want to make a service available to the public.
What you might be looking for is what is known as TCP hole punching. But in most cases that still requires you to have a public third-party public service that can let the two locations exchange their public endpoint information.
Alternatively Universal Plug and Play (UPnP) might allow you to request the router to port-forward automatically. But this is not something I have worked with myself.

Multiple UDP connections to different remote IPs with the same port

I have a need to talk to multiple devices on a private LAN using a proprietary UDP protocol. In a production setting we have a industrial PC running a C++ application that can connect to multiple devices and communicate freely with them. I am trying to duplicate that communication using C# for a windows application that technicians, testers and others would be using. I have probably done this myself a thousands times in c++ but c# seems to be giving me all sorts of fits.
I have one UDP listener listening on Any IP and specific Port. This port is different from the device command port. This receives a periodic heartbeat from each device. From this communication I am able to get the specific IP and command Port for that device. The program maintains a list of devices and displays that lists to the user. The user can then select a specific device and inspect it more for more details.
If there are several devices with the same port number the program will not be able to inspect those devices at the same time. When the user selects the device the program creates a new instance of the UdpClient. In pseudo-code form:
udpConnection = new UdpClient();
udpConnection.ExclusiveAddressUse = false;
udpConnection.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpConnection.Client.Bind(localEndpoint);
udpConnection.Client.Connect(remoteEndpoint);
Local Endpoint is the Local interface IP and the Device Port Number of the machine the application is running on. Remote EndPoint is the Device IP and Device Port that the application wants to inspect further.
As anyone had similar issues and what have you done to get around it?
Thanks in advance
Update sample network diagram and further explanation:
Network Diagram
In the image I will be able to have two windows viewing Device A and C or B and C simultaneously with no issues. However if I have Device A and C the window that I opened second will not get any communications updates until I close the first window. If I "sniff" the network with WireShark I see all the communications as I would expect.
Code Snippet:
private void ClientThread()
{
IPEndPoint myEndPoint;
myLogger = LogManager.GetLogger("ClientLogs");
myLogger.Debug("Client Started!");
IPAddress ClientAddress = System.Net.IPAddress.Parse(ClientIP);
myIP = "10.0.0.4"; // Currently hard-coded local interface IP
IPAddress thisAddress = System.Net.IPAddress.Parse(myIP);
ClientEndPoint = new IPEndPoint(ClientAddress, Convert.ToInt32(ClientPort));
myEndPoint = new IPEndPoint(thisAddress, Convert.ToInt32(ClientPort)); // Both forms launch but only the first one will receive data.
//myEndPoint = new IPEndPoint(thisAddress, 0); // Both forms will launch but no data received (packets do show being received in wireshark)
//myEndPoint = new IPEndPoint(IPAddress.Any, ClientPort); // Both forms launch but only the first one will receive data.
try
{
myUDP = new UdpClient();
myUDP.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // "Only one usage of each socket address (protocol/network address/port) is normally permitted" Exception when removed.
myUDP.ExclusiveAddressUse = false; // No difference if this is removed
myUDP.Client.Bind(myEndPoint); // Neither form will receive data if this is removed
myUDP.Client.Connect(ClientEndPoint); // removing this will allow the forms to launch but again the only the first will receive data
}
catch (Exception ex)
{
myUDP = null;
myLogger.Fatal(String.Format("Error in setting up UDP Client: {0}", ex.Message));
return;
}
myLogger.Debug(String.Format("Attempt to connect to : {0} on {1}", ClientIP, Convert.ToInt32(ClientPort)));
byte[] bytes = new byte[1452];
try
{
while (ThreadLoop)
{
IPEndPoint newEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = myUDP.Receive(ref newEndPoint);
ParseProtocolPacket(ref receiveBytes); // Code to parse the data received
}
}
catch (Exception Ex)
{
myLogger.Debug("Client Socket Other Error: " + Ex.Message);
}
}
I think your problem is here:
udpConnection.Client.Bind(localEndpoint);
This line, if I understand correctly, is telling it to use the same local port to make the outbound request. But you already have another UdpClient listening on that port, so Windows won't know which one to send the traffic to (or it just sends it to the first one).
You should be able to just not use Bind() here. Without it, when you call Connect(), it will assign a random local port, which is the way most outbound network requests work.
Or if you need to specify the network interface, then pass 0 for the port and Windows will assign one:
localEndpoint = new IPEndPoint(ipAddress, 0);

WIFI Direct IP Address issue

I have checked and found that the problem is the ip address being assigned to the connectionEndpointPair is carrying the IP of the wi-fi direct network adapter and i don't know how to open the port on that specific ip, the ip is different from when i ping it from my pc the windows is listening on port 5009 and connection established when i use the wi-fi ip but when i use the wi-fi direct ip addresses i'm having an issue
The wi-fi direct connection between the device and the windows 8.1 application is ok, I then am awaiting for my sockets to connect but it does not happen what could be the issue ?
I get error on Visual Studio:
No connection could be made because the target machine actively refused it. (Exception from HRESULT: 0x8007274D)
On the Windows side i am using this code:
String deviceSelector = WiFiDirectDevice.GetDeviceSelector();
DeviceInformationCollection deviceCollection = await DeviceInformation.FindAllAsync(deviceSelector);
if(deviceCollection.Count > 0)
{
try
{
wfdDevice = await WiFiDirectDevice.FromIdAsync(deviceCollection[0].Id);
wfdDevice.ConnectionStatusChanged +=ConnectionStatusChangedNotficationHandler;
var endpointPairs = wfdDevice.GetConnectionEndpointPairs();
EndpointPair connectionEndpointPair = endpointPairs[0];
try
{
connectionEndpointPair.RemoteServiceName = "5009";
StreamSocket socket = new StreamSocket();
await socket.ConnectAsync(connectionEndpointPair);
string s = "hello";
}catch (Exception err)
{
string s = err.Message;
s = err.StackTrace;
}
}
catch (Exception err)
{
string error = err.Message;
}
On the android side i am using this code:
private void initiateClientSocket(String hostAddress) {
int timeout = 10000;
int port = 5009;
InetSocketAddress socketAddress
= new InetSocketAddress(hostAddress, port);
try {
Socket socket = new Socket();
socket.bind(null);
socket.connect(socketAddress, timeout);
} catch (IOException e) {
Log.e(TAG, "IO Exception.", e);
}
// TODO Start Receiving Messages
}
From the android side I am getting:
java.net.UnknownHostException: Host is unresolved: my ip
Can any please help
Thanks :)
Even if you have a direct WIFI Connection between the Android phone and the windows computer, you need a server and a client for a tcp connection.
I don't know the purpose of your application but I assume that the windows computer is the better choice for the server. So instead connecting to the socket, on the computer you should open a listener for the port.
The server class that is related to the chosen StreamSocket class is the StreamSocketListener. You can find the Documentation here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.sockets.streamsocketlistener.aspx
There is also a paragraph in this documentation about the typical order of operations:
Create the StreamSocketListener.
Use the Control property to retrieve a StreamSocketListenerControl object and set the socket quality of service required.
Assign the ConnectionReceived event to an event handler.
Call the BindServiceNameAsync or BindEndpointAsync method to bind to a local TCP port or service name.
When a connection is received, use the StreamSocketListenerConnectionReceivedEventArgs object to retrieve the Socket property with the StreamSocket object created.
Use the StreamSocket object to send and receive data.
Call the Close method to stop listening for and accepting incoming network connections and release all unmanaged resources associated with the StreamSocketListener object. Any StreamSocket objects created when a connection is received are unaffected and can continue to be used as needed.
I haven't worked with this special class, but the basics of TCP are always the same...
I don't quite understand your code on Window, but guess that there is something wrong with the following code
connectionEndpointPair.RemoteServiceName = "5009";
It seems that "RemoteServiceName" has nothing to do with the port number 5009. Please check other fields in the struct/object "connectionEndpointPair" and make proper settings.

Using C# UDP Client

I'm making a program which needs to be listening for UDP Data at all times.
My current idea is have this method running constantly in one thread listening for packets and then adding them to a list ready to be dealt with in other threads. The main problem is I would also like to add the received IP to a list so that the other thread can deal with it but I don't know if the program stops using the Receive method for a moment if it will lose packets received while processing the data or if it can still grab them from a queue.
public void listen()
{
try
{
packetQueue.Add(receivingUdpClient.Receive(ref RemoteIpEndPoint));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
network traffic should be buffered on your network card so the data should be consistent even if you are listening inconsistently. as for the IP you can get it from the endpoint so you'll need to pass that as well:
public void listen()
{
try
{
packetQueue.Add(receivingUdpClient.Receive(ref RemoteIpEndPoint), RemoteIpEndPoint);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
If you want to miss as little time as possible in between receives I suggest you use BeginReceive and start a new BeginReceive in the callback before processing the received data in the callback. this will add some synchronization complexity though.
I know of no way to get the IP from the Udp packet. You need to get it form the EndPoint:
byte[] receivedBytes = oClientListener.Receive(ref endPoint);
IPAddress = endPoint.Address;
PackQueue.Add( new PacketOfSomeType( receivedBytes, IPAdress ) );
Also, your program will need to run VERY SLOWLY to start losing any packets - windows will buffer those for you, so long as you have your client listener set up!

Categories