C# UDP Multicast with multiple clients - only receiving message from one client - c#

So I have created a simple UDP server that broadcasts a datagram to clients via multicast. Upon receiving this message, each client responds by sending a multicast datagram reporting some internal state.
Only the server is interested in the message sent by the clients, although the clients and servers all use the same UDP send/receive code.
My issue is that with multiple clients I only ever seem to receive a datagram from one client. The other client's messages are never received even though they are sent.
I am using Microsoft's UdpClient and listening for messages on a separate thread using UdpClient.Receive(IPEndpoint endpoint).
My UdpClient is initialised as follows:
_ipEndpoint = new IPEndpoint(ipAddress, port);
_udpClient = new UdpClient(port, ipAddress.AddressFamily) { MulticastLoopback = false, DontFragment = true };
_udpClient.JoinMulticastGroup(ipAddress);
Listening is as follows, called within a while loop on a separate thread:
public bool ReceiveMessage(out BaseMessage message)
{
try
{
byte[] dataBuffer = _udpClient.Receive(ref _ipEndpoint);
message = UdpSerializer.ByteArrayToObject(dataBuffer);
}
...
Any ideas?

Related

UDP NAT Hole Punching on separate UdpClient objects

I believe I am having an issue with NAT hole punching via UdpClient objects. I have a simple class that looks like:
class UdpConnection
{
UdpClient udpSend { get; set; }
UdpClient udpRecv { get; set; }
IpEndPoint TargetEndPoint { get; set; }
UdpConnection(IPEndPoint targetEndPoint)
{
TargetEndPoint = targetEndPoint;
}
void SendTo(byte[] bytes)
{
udpSend.Client.SendTo(bytes, TargetEndPoint);
}
void TryToConnect () { // ... // }
void WaitForConnect () { // ... // }
}
A client will use one of these objects and call TryToConnect(). The client will then use UdpConnection.udpRecv.Client.SendTo() to send a Hello packet to the server and then sleep for a second waiting for a response. When the Hello is acknowledge it then uses UdpConnection.udpRecv only for listening, updates the UdpConnection.udpSend object to use the target port given by the server to send further data and is then considered connected.
A server uses a dedicated UdpClient object to listen on for new connections. When it receives a new remote address it creates a new UdpConnection object with the new address, creates an Acknowledgement packet providing the specific port for this new connection to send data to and then listen on that port and send the Acknowledgement packet.
This all works when ran locally but the client will fail to receive the Acknowledgement packet when ran remotely. What makes me think this is a NAT Hole punching issues is that if I send the acknowledgement back on the server's listening port, the one that received the new connection, the client receives it. This makes me feel like I am missing something.
Where have I gone wrong? Is it that I am attempting to hand off the response to a new UdpClient instead of the one the client connected to? Do I have to handle the whole handshake on the Listening Port until the client uses its new dedicated port on the server?

C# .Net Socket Server Client

I've got a little problem with the .Net Sockets in C#.
I programmed a client and a server working with TCP.
As the client is opened it sends a handshake to the server. The server answers with it's state (clientexists, clientaccepted,...). After that the application sends a getdata-request, abandons the connection and listens for the server's 'response'. Now, the server builds a connection to the client and sends all the data the client needs.
The code and everything else works, but the problem:
On our company testserver it works fine, on the live server only the handshake works. After it the client doesn't receive any more data. Serverapplication is the same on both servers.
I thought the problem was caused by some firewall (server wants to build a tcp connection to the client -> not good), but the system administrator said there is no firewall that could block that.
Now I'm searching for a ('cheap') solution that doesn't take too much time and changes in code. If anyone knows how to theoretically solve that, that would be great.
BTW: I am not allowed to do anything on the live server other than run the serverapplication. I don't have the possibility to debug on this server.
I can't publish all of my code, but if you need to see specific parts of it, ask for it please.
---EDIT---
Client-Server communication
1) Client startup
Client send handshake (new tcp connection)
2) Server validates handshake and saves IP
Server responds with it's client state (same tcp connection)
3) Client acknowledges this response and abandons this connection
Client sends getdata-request (new tcp connection)
Client abandons this tcp connection, too
4) Server receives getdata-request and collects the needed data in the main database
Server sends all the collected data to the client (multiple tcp connections)
5) Client receives all data and displays it in it's GUI (multiple tcp connections and the order of the data is kept by working with AutoResetEvents and Counts of sockets to send)
This is the main part my code does. It's by far not the best but it was for me as I wrote it I guess. Step one, two and three work as intended. The processing of the data works fine, too.
Another thing i forgot to mention is that the solution uses two Ports '16777' and '16778'. One to receive/listen and one to send.
My code is based on the MSDN example of the asynchronous server and client.
Sending a handshake (and getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
Server listener
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
Socket send
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket send all data part (answer to getdata-request | socToHandle should be the socket of the previous connection of the getdata-request)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
Looking through my old code I have one idea =>
Could I send everything over the same connection by changing:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(which creates a new connection) to something that uses the same connection?
If that would work, how can I do that?
And would the listener part of the client still receive single packets?
Servers and their environment are configured to handle incoming requests properly. Clients are usually behind a router, which by default make them unable to receive incoming connections from outside their network (a good thing).
To enable incoming connections, you could configure your router to forward all requests for a certain port number to your machine. No one else on your network would be able to run the client then, though.
This is why in a typical multiple clients-single server environment, the client makes all the connections, and only the server requires any changes to the network landscape.
I don't know why you chose to connect to the clients from the server side, but I would strongly advise against this - any cheap solution that uses this mechanism may turn out to be very expensive in the end.

UdpClient Receive not receiving datagram

I trying to write a TFTP client for a class project.
Using the UdpClient class I can successfully request data from the server but the returned packet never reaches my code.
My firewall is turned off.
I can observe the returned packet in wireshark but UdpClient.Receive blocks indefinitely.
mUdpClient is initialized like this in the constructor: mUdpClient = new UdpClient();
mUdpClient is connected like this
public void connect(String host, int port) {
mServerAddress = System.Net.Dns.GetHostAddresses(host)[0];
var endPoint = new IPEndPoint(mServerAddress, port);
mUdpClient.Connect(endPoint);
}
After the connect I send my request which is successful (as observed in wireshark)
This is what my receive code looks like
private void receiveResponse() {
var newEndpoint = new IPEndPoint(IPAddress.Any, 0);
byte[] response = mUdpClient.Receive(ref newEndpoint);
Console.Out.WriteLine(response);
}
This has been tested on my Surface Pro and a Windows 8.1 VirtualBox VM running under Debian.
Note that since you are using the Connect() method on your UDP socket, you will only see datagrams actually sent from that IPEndPoint. If your remote host for some reason uses a different IPEndPoint to send data back to you, you won't see it. So maybe try not using the default host feature (i.e. don't call Connect...just provide the remote IPEndPoint on each Send() call).

Flowcode Transmits UDP but Unsuccssefully read by the server

I'm using Flowcode technology to program a micro controller 16F877A.
from flowcode i'm sending 3 bytes UDP packets to a server listening on port 23456.
the problem is that the server never receives those packets. i used wireshark for tracing and it was able to detect the 3 bytes and its content.
below is my server code using c#
const int port_number=23456;
TcpListener server=new TcpListener( IPAddress.Any ,port_number);
Socket soc;
NetworkStream s;
bool exit=false;
Thread mythread;
thread code is here
void method()
{
try
{
server.Start();
soc = server.AcceptSocket();
s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
textBox1.Text += sr.ReadLine();
if(soc.Connected==true && exit==false)
method();
}
catch(Exception es)
{
Console.WriteLine("{0}",es.Message);
}
}
do you think i need to change anything to be able to read those 3 bytes and process them.
i really appreciate your help.
You are using a TcpListening, but you are sending UDP packets? Try the UDPClient class: http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.aspx
Edit
To elaborate a little bit. A TCP Client will never receive UDP packets, since TCP and UDP are two separate protocols at the socket level. The socket will see you are listening for a TCP connection, it will receive the UDP datagram, see no listeners, and throw it away.

Why UDP socket subscribed to a multicast group is picking up a non-multicast message?

Overview: I have set up a server and a client, where both attempt discovery of each other using UDP. When the server starts up it sends a multicast message (239.1.1.1) that it is alive. When the client starts up it sends a multicast message (239.1.1.2) that it is alive. Both server and client are subscribed to each other's multicast messages to receive their transmissions. This way, regardless of which application (server or client) starts up first, one or the other will be notified of their existence.
On the client side I do the following:
Set up a listening socket to subscribe to and receive server originated multicast messages.
Set up a receiving socket to receive server responses to client's multicast
message per #3 below.
Send a muticast message (for server to receive and respond to) that client is running.
Receive server response to clients multicast message sent in #3.
Question: Everything is working fine, except that both receiving sockets end up getting the server's (non-multicast) response to the client. I am not clear if this is expected behavior or not. Can I reduce the two receiving sockets to one? #1 is subscribed to the server's multicast and #2 is simply listening for a direct transmission from the server on the same port (non-multicast message from server). Can I safely remove the second receiving socket?
See source code below (I removed exception handling for simpler code presentation).
Client code:
// 1. Set up a socket and asynchronously listen for server startup multicasts.
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
listenSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, 1);
listenSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
listenSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse("239.1.1.1")));
EndPoint clientEndPoint = new IPEndPoint(0, 0);
listenSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, ref clientEndPoint,
new AsyncCallback(OnServerMessageReceived), (object)this);
// 2. Set up socket to receive the server's response to client's multicast.
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
receiveSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, 1);
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
receiveSocket.ReceiveTimeout = 3000; // Timeout after 3 seconds.
// 3. Send a multicast message for server to respond to.
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
EndPoint multicastEndPoint = new IPEndPoint(IPAddress.Parse("239.1.1.2"), 50000);
sendSocket.SendTo(packet, packet.Length, SocketFlags.None, multicastEndPoint);
// 4. Wait for server to respond to the multicast message (timeout = 3 seconds).
byte[] receiveBuff = new byte[2048];
EndPoint serverEndPoint = new IPEndPoint(0, 0);
int bytesRead = receiveSocket.ReceiveFrom(receiveBuff, ref serverEndPoint);
Server code:
// Receive multicast message sent from client (in asynchronous callback method).
EndPoint clientEndPoint = new IPEndPoint(0, 0);
int bytesRead = listenSocket.EndReceiveFrom(asyncResult, ref clientEndPoint);
// Send response back to the client (change port to 50000).
EndPoint destination = new IPEndPoint((clientEndPoint as IPEndPoint).Address,
50000);
Socket responseSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
responseSocket.SendTo(response, response.Length, SocketFlags.None, destination);
The answer to your question is "Yes, this is expected behaviour". You don't need to open a seperate socket to recieve unicast packets on the same port.
PS
It seems like overkill to have your servers join a multicast group to listen for new clients - you could just have the servers regularly transmit a beacon to the client multicast address saying "I am here" (say, once every 30 seconds).
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
Your receive sockets are binding to ANY address, which means they will receive unicast, broadcast and multicast traffic. You can bind to an interface address to just receive unicast traffic, and you can bind just to the multicast group to only receive multicast traffic.
When sending a UDP datagram you can specify the destination address which may be multicast or unicast. You can therefore reduce both the server and client code to one socket each.
Whilst I'm not sure it's addressing your issue, I would expect both client and server to talk on the same IP multicast address (e.g. 239.1.1.1). At the moment it looks like you've given the client and server one address each, and what happens if/when you introduce a new client ?
Better option would be to use a service discovery protocol like Bonjour or Avahi than rolling your own, as they have solved a lot of problems already.

Categories

Resources