UDP Multicast between two sockets in the same process - c#

I'm writting some tests for classes that handles UDP multicast communication.
I designed the tests to use the loopback interface (127.0.0.1) for the tests because I don't want the them to interfer with other programs/devices on the network.
In my "unit test" I have a tested socket that joins a given multicast group and binds to 127.0.0.1 and a sender
socket that also joined the same multicast group and binds to 127.0.0.1, both of course in the same process.
To be sure that the message is sent I have another test program (so another process) that also joins the multicast group and outputs everything that is sent to it.
The problem is that my tested socket never receive what the sender sent BUT the test program (so another process) receives it.
Are there some limitation with the combination multiple sockets/multicast/localhost?
New information:
My mistake was to consider that UDP on localhost might be reliable. The below test program shows that the first UDP packet is never received (at least on my computer) by my listening socket (but the other process still receives it).
In my unit tests I am sending one packet and expects specific answers: I cannot afford sending the message two times and receiving the answer only once.
It seems to work reliably if I wait for the first receive timeout to occur before sending the first packet.
Does anyone have an idea why the first UDP packet never arrives?
Here's the code I used in my trials:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using NUnit.Framework;
namespace MulticastTest
{
[TestFixture]
public class Program
{
static void Main(string[] args)
{
new Program().Run();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
[Test]
public void Run()
{
_waitFirstReadTiemout = new AutoResetEvent(false);
IPAddress lMulticastAddress = new IPAddress(0xFAFFFFEF);
IPEndPoint lRemoteEndPoint = new IPEndPoint(lMulticastAddress, 1900);
// Create sender socket
Socket lSendSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
// Allow to share the port 1900 with other applications
lSendSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress,
true);
// Set TTL for multicast packets: socket needs to be bounded to do this
lSendSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.MulticastTimeToLive,
2);
// Bind the socket to the local end point: this MUST be done before joining the multicast group
lSendSocket.Bind(new IPEndPoint(IPAddress.Loopback, 55236));
// Join the multicast group
lSendSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.MulticastLoopback,
true);
lSendSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
new MulticastOption(lMulticastAddress));
// Create receiver and start its thread
Thread lReceiveThread = new Thread(ReceiveThread);
lReceiveThread.Start();
int i = 0;
while (!fStop)
{
if (i == 0)
_waitFirstReadTiemout.WaitOne(10000);
byte[] lToSend = Encoding.ASCII.GetBytes(DateTime.Now.ToString("yyyyMMdd HHmmss"));
lSendSocket.SendTo(lToSend, lRemoteEndPoint);
Console.WriteLine("Sent #" + (i + 1) + ": " + DateTime.Now.ToString("yyyyMMdd HHmmss"));
Thread.Sleep(1000);
try
{
if (Console.KeyAvailable || i >= 10)
fStop = true;
}
catch (InvalidOperationException)
{
fStop = i >= 10;
}
finally
{
++i;
}
}
}
private AutoResetEvent _waitFirstReadTiemout;
private bool fStop;
private void ReceiveThread()
{
Socket lSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
// Allow to share the port 1900 with other applications
lSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress,
true);
// TTL not required here: we will only LISTEN on the multicast socket
// Bind the socket to the local end point: this MUST be done before joining the multicast group
lSocket.Bind(new IPEndPoint(IPAddress.Loopback, 1900));
// Join the multicast group
// If the local IP is a loopback one, enable multicast loopback
lSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.MulticastLoopback,
true);
lSocket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.AddMembership,
new MulticastOption(
new IPAddress(0xFAFFFFEF)));
lSocket.ReceiveTimeout = 1000;
byte[] lBuffer = new byte[65000];
int i = 0;
while (!fStop)
{
try
{
int lReceived = lSocket.Receive(lBuffer);
++i;
Console.WriteLine("Received #" + i + ": " + Encoding.ASCII.GetString(lBuffer, 0, lReceived));
}
catch (SocketException se)
{
_waitFirstReadTiemout.Set();
Console.WriteLine(se.ToString());
}
}
}
}
}

This most likely is a race between your sending and receiving threads - you send the first packet before the receiver joins the group. This explains why it works with a timeout.

You may need to enable loopback mode on the socket.

Related

How can I make every client be aware of every other client connected to the same UDP network?

I would like every client to 'be aware of' every other client that has connected within the UDP network at request.
So far I have a very simple program where every client inputs a username and sends it to the network. Every client stores a list of usernames to keep track of who has communicated with the network at least once. If a new username pops in, it outputs it to the console and stores it in the list as to prevent from outputting it again.
This is all fine and dandy but I've only managed the above by having every client continuously awaiting new data from the network (because it can never know when new clients will stop 'entering' the network).
Here's all the code. The part of interest is probably the displayAllUsers() function.
I've pasted the whole program because it is (i) very short (ii) my knowledge of UDP within C# is very green, and my practices are in no way good, so maybe it is a good idea to have readers be aware of that.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Node
{
class Program
{
static UdpClient client = new UdpClient();
static IPEndPoint localIP;
static IPEndPoint remoteIP;
static String currentUser;
static List<String> currentUsers = new List<String>();
static void Main(string[] args)
{
initialiseListener();
initialiseWriter();
Console.WriteLine("What's your username?");
currentUser = Console.ReadLine();
Byte[] buffer = Encoding.Unicode.GetBytes(currentUser);
//Who is current user?
client.Send(buffer, buffer.Length, remoteIP);
Console.WriteLine("Here are all active users:");
displayAllUsers();
}
private static void displayAllUsers()
{
Byte[] buffer;
while (true)
{
Byte[] data = client.Receive(ref localIP); //blocking call - continuously listening
string strData = Encoding.Unicode.GetString(data);
if (!currentUsers.Contains(strData)) //if data is not found in current users list...
{
Console.WriteLine(strData); //write username on screen
currentUsers.Add(strData); //and add to current users list
buffer = Encoding.Unicode.GetBytes(currentUser); //Convert currentUser to bytes
client.Send(buffer, buffer.Length, remoteIP); //and send new current user to everyone else
}
}
}
private static void initialiseWriter()
{
IPAddress multicastAddress = IPAddress.Parse("239.0.0.222");
client.JoinMulticastGroup(multicastAddress);
//Send data to this multicast address group
remoteIP = new IPEndPoint(multicastAddress, 2222); //To write to the multicastAddress group on port 2222
}
private static void initialiseListener()
{
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.ExclusiveAddressUse = false;
//More than one client can use the port to be specified
localIP = new IPEndPoint(IPAddress.Any, 2222); //To listen on any IP Address available from the port 2222
client.Client.Bind(localIP); //Associate client with listener
}
}
}
Ideally, each client would be able to request the displayAllUsers() device whenever and have such list generated for them, rather than constantly awaiting new clients to join in.
Eventually I'd like to implement my knowledge of UDP and non-centralized networking to an Xamarin app and have every device be aware of every other device that has such app open.
I have found a solution from here and modified the below in my displayAllUsers() method.
if(client.Available > 0){
data = client.Receive(ref localIP); //blocking call - continuously listening
}else{
break;
}
Using the .Available property proved to be very useful as it checks if there is something to listen to -- just what I needed.
I will mark this as the thread's answer if it is found to be good practice.

Get random free opened port for tests

I'm running some integration tests with REST API service.
The problem is that sometimes hardcoded port isn't free at the moment the test starts for the next time. Because it was opened by previous test and isn't closed by the system yet.
I use OWIN, the application is shut down at the moment the next test starts.
Could you please suggest me a good way to determine a free port on the system without opening it in advance and then closing it? Or say that it's not possible.
Because it could be not freed by the system yet, just as it happens already.
As an alternative to TempoClick's answer, we can use the IPGlobalProperties.GetActiveTcpListeners() method to test if a port is available - without trying to open it in advance. GetActiveTcpListeners() returns all active TCP listeners on the system, and so we can use it to determine if a port is free or not.
public bool IsFree(int port)
{
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] listeners = properties.GetActiveTcpListeners();
int[] openPorts = listeners.Select(item => item.Port).ToArray<int>();
return openPorts.All(openPort => openPort != port);
}
Note that GetActiveTcpListeners() doesn't return listening UDP endpoints, but we can get them with GetActiveUdpListeners().
So, you can start with the default port (or select a random value) and keep incrementing until you find a free port with the IsFree method.
int NextFreePort(int port = 0)
{
port = (port > 0) ? port : new Random().Next(1, 65535);
while (!IsFree(port))
{
port += 1;
}
return port;
}
A simple test:
using System;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Linq;
class Test
{
static void Main(string[] args)
{
int port = 1000;
Console.WriteLine(IsFree(port));
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
server.Start();
Console.WriteLine(IsFree(port));
Console.WriteLine(NextFreePort(port));
}
static bool IsFree(int port)
{
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] listeners = properties.GetActiveTcpListeners();
int[] openPorts = listeners.Select(item => item.Port).ToArray<int>();
return openPorts.All(openPort => openPort != port);
}
static int NextFreePort(int port = 0) {
port = (port > 0) ? port : new Random().Next(1, 65535);
while (!IsFree(port)) {
port += 1;
}
return port;
}
}
A different approach is to use port zero. In this case, the system will select a random free port from the dynamic port range. We can get the number ot this port from the LocalEndpoint property.
TcpListener server = new TcpListener(IPAddress.Loopback, 0);
server.Start();
int port = ((IPEndPoint)server.LocalEndpoint).Port;
Console.WriteLine(port);
To get a free port
static int FreePort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
When using t.m.adam's
NextFreePort(...) method, the port may be free, but not permitted. In my case, this happened under Linux. The following method tests, whether the free port can actually be used:
static bool CanBindPort(int port)
{
try
{
var localEndPoint = new IPEndPoint(IPAddress.Any, port);
using var listener = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
}
catch
{
// e.g. because of "Permission denied" or other reason
return false;
}
return true;
}
This is, however, not the requested solution for "without opening the port in advance".
The following one-liner (taken from this SO post), uses Python to quickly open and close a socket on port 0. When you do this in Python, it automatically selects an open port, which gets printed out to the screen:
python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'

C# SocketException when accepting connections

I have been trying to learn about sockets for the past day or so. I thought it would be a good idea to make a basic chat client and server to learn with, I have tried to make an asynchronous server so I don't need to use loads of threads etc and I have came into an issue I simply can't fix. When I start my server, it goes through all ok and waits at the point where it needs to wait for a connection. I then start up my makeshift 'client' that simply sends a string for now and my server crashes with a SocketException with the message
Additional information: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
I don't see how my socket is not connected when it has to accept the connection in the first place. I have been using this tutorial (https://msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx) as a guide and have looked at both my code and the tutorial and still don't understand what I am doing wrong, can anyone help me?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Chat_Application
{
class Server
{
private Socket serverSocket = null;
private volatile ArrayList connections = null; // will hold all client sockets
private const int port = 1090;
private IPAddress ipAddress = null;
private IPEndPoint ipEndPoint = null;
private Thread listenThread = null; // seperate thread to run the server
private ManualResetEvent allDone = null;
public Server()
{
this.serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.connections = new ArrayList();
ipAddress = IPAddress.Parse(GetLocalIPv4(NetworkInterfaceType.Ethernet));
ipEndPoint = new IPEndPoint(ipAddress, port);
listenThread = new Thread(StartListen);
allDone = new ManualResetEvent(false);
}
public void Start()
{
listenThread.Start();
}
public void StartListen()
{
this.serverSocket.Bind(ipEndPoint);
this.serverSocket.Listen(20);
Program.mainWin.console.Text += "\n<INFO> Socket bound, listening for connections...";
while (true)
{
allDone.Reset();
serverSocket.BeginAccept(new AsyncCallback(AcceptConnectionAsync), serverSocket);
Program.mainWin.console.Text += "\n<INFO> Conncetion accepted...";
allDone.WaitOne();
}
}
public void AcceptConnectionAsync(IAsyncResult AR)
{
Byte[] bufferBytes = new byte[1024];
allDone.Set();
Socket client = (Socket) AR.AsyncState;
int x = client.Receive(bufferBytes);
Program.mainWin.console.Text += System.Text.Encoding.Default.GetString(bufferBytes);
}
public string GetLocalIPv4(NetworkInterfaceType _type)
{
string output = "";
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
{
if (item.NetworkInterfaceType == _type && item.OperationalStatus == OperationalStatus.Up)
{
foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
output = ip.Address.ToString();
}
}
}
}
return output;
}
}
}
You're never calling EndAccept (from the example you linked):
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar); // This right here
The socket in ar.AsyncState is the listening socket, not the connected client. AsyncState is an arbitrary object you can use to pass information to the callback method (AcceptConnectionAsync). In this case, you are passing the serverSocket (the second parameter below):
serverSocket.BeginAccept(new AsyncCallback(AcceptConnectionAsync), serverSocket);
When you call EndAccept on the listening socket, you are getting a new Socket instance that is a specific connection to the client -- your listener socket will start the asynchronous request to accept another connection in your while loop in StartListen. The socket returned by EndAccept is in a connected state and ready to communicate with the other endpoint, based on this specific callback invocation (hence, the requirement to supply IAsyncResult as an argument).
This is referred to as the Asynchronous Programming Model. MSDN has some great information on this (as usual).

UDP Latency, Multiple Endpoints unicast

I need to send the same datagram to many endpoints using UDP and the network does not support multicast, ONLY unicast.
To test I created a list of endpoinst (fake IPs in the supported address range) and one valid machine returning echo at the end of the list.
The goal is to measure end to end latency.
Using WireShark I see that the UDP messages are serialized very fast on the sender, but it takes long to receive the message.
Are Windows UDP sockests combined together and sent over the NIC after some time or condition occurs? How do I flush each datagram?
I see NoDelay and LingerOptions don’t apply for UDP, but is looks like it is lingering before sending.
Pseudo code:
Generate List (5000 endpoints)
Add Echo device at the end of the list
Foreach (var ep in endpointList) {SendDataRetries(ep, payload);}
public void SendDataRetries(string downlink, IPEndPoint ep, int retries)
{
if (string.IsNullOrEmpty(downlink))
return;
Byte[] sendBytes = Encoding.ASCII.GetBytes(downlink + "\r\n");
for (int x = 0; x < retries; x++)
{
try
{
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
server.DontFragment = true;
server.SendTo(sendBytes, ep);
server.Close(); //is this really needed to flush the write?
}
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("\n\nException\ndownlink:{0}\nep:{1}\nex:{2}", downlink, ep, ex));
x--;
}
}
}

Sending and receiving UDP packets between two programs on the same computer

Is it possible to get two separate programs to communicate on the same computer (one-way only) over UDP through localhost/127... by sharing the same port #?
We're working on a student project in which we need to send UDP packets containing some telemetry between two computers. The program that generates these packets is proprietary, but I'm working on the receiver program myself with C# using System.Net.Sockets.UdpClient and System.Net.IPEndPoint.
This works fine during our group's meetings when we have multiple computers connected on which we can run the two programs separately. But it's not very useful when I'm home and trying to expand on the telemetry processing program as I only have one computer (I need a feed for testing the processing program). I can not install the program on any of the school's computers either.
When I try to run both programs on my computer at the same time (starting my program last) I get a SocketException saying that only a single use of each port is normally allowed. Which leads me to believe there must be some way to share the port (although it makes sense that only a single program can use port on a computer at any one time, I have no trouble running multiple internet browsers at the same time (and I suppose they use port 80 for http)).
REEDIT of the EDIT:
sipwiz was right, and thanks to Kalmi for the pointer to UdpClient.Client.Bind().
At the time, though, we are considering using another program that generates similar packets, and with which we are able to share port with on the same computer using my first (although naive) approach with the UDP client binding in the ctor.
Sorry for having to unmark your answer, sysrqb.
You can bind to a port multiple times using the ReuseAddress socket option.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
You'll need to set the same option on the UDP server socket as well.
I did not expect this to be possible, but.. well.. sipwiz was right.
It can be done very easily. (Please vote sipwiz's answer up!)
IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 6000);
//Failed try
try
{
var u = new UdpClient(5000);
u.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpClient u2 = new UdpClient(5000);//KABOOM
u2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
catch (Exception)
{
Console.WriteLine("ERROR! You must call Bind only after setting SocketOptionName.ReuseAddress. \n And you must not pass any parameter to UdpClient's constructor or it will call Bind.");
}
//This is how you do it (kudos to sipwiz)
UdpClient udpServer = new UdpClient(localpt); //This is what the proprietary(see question) sender would do (nothing special)
//!!! The following 3 lines is what the poster needs...(and the definition of localpt (of course))
UdpClient udpServer2 = new UdpClient();
udpServer2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer2.Client.Bind(localpt);
Here is the full code from the answers by Tarnay Kálmán and sipwiz:
The server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace UdpBroadcastTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Sender");
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Connect("localhost", 11000);
try
{
string message = String.Empty;
do
{
message = Console.ReadLine();
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes(message);
udpClient.Send(sendBytes, sendBytes.Length);
} while (message != String.Empty);
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Press Any Key to Continue");
Console.ReadKey();
}
}
}
The client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace UdpReciever
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Receiver");
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 11000));
try
{
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
string message = String.Empty;
do
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
message = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received: " +
message);
//Console.WriteLine("This message was sent from " +
// RemoteIpEndPoint.Address.ToString() +
// " on their port number " +
// RemoteIpEndPoint.Port.ToString());
}
while (message != "exit");
udpClient.Close();
//udpClientB.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Press Any Key to Continue");
Console.ReadKey();
}
}
}
You might be able to put multiple IP addresses on your network card, or loopback, and bind the server and client to different IP addresses?
Or else the Virtual machine approach will definitely work.
Only one program can bind to a port at a time. Multiple programs can connect to one port on another system's, but the local port your different web browsers have bound themselves to is randomly assigned.
Unless you want to do some ugly inter-process communication or packet sniffing, there's no way to have multiple programs bound to one port.
Even changing your code so that I can pass in an IP address I gets the same error message it appears that you can't bind to the same port and only one port can be used
here is the sample code I used your example and Altered it to capture my ip from my local machine..
IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0];
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 11000);
//IPEndPoint localpt = new IPEndPoint(ipLocalEndPoint);
UdpClient udpServer = new UdpClient(ipLocalEndPoint);
udpServer.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer.Connect(ipLocalEndPoint);
UdpClient udpServer2 = new UdpClient();
udpServer2.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer2.Client.Bind(ipLocalEndPoint); // <<---------- Exception here
this will produce the exception on the Bind () method.. sorry.
My advice: don't pass the port number into the UdpClient constructor. From the documentation, (somewhat sparse, I know...) it looks like if you do, the UdpClient will try to bind to that port (which, as sysrqb mentioned, is not allowed). (If you don't, I believe the UdpClient will listen on a random port for any replies. You could also pick a port you know to be unused.)
When you call Connect() you need to pass in the port number the server is listening on.
bind the two programs,ie, the sender and receiver to the same port on the localhost.dats the simple answer.

Categories

Resources