udp packet not coming through - c#

I have the following setup:
Dedicated server --> Internet --> Modem (telenet) --> Router --> client
The client initiates a tcp connection with the server to register itself on the server, and gives through following info:
mac address of the client
external ip; this is retrieved by using webclient string download from whatsmyip.org
Some updates occur on the server and of course the client needs to be notified, so the client can start a sync session on its own:
To notify the client, the server sends a udp packet from the server to the modem (to the external ip, earlier received from the client), in the meanwhile the client is listening for udp packets behind the router.
The problem is that I'm not receiving any packets.. Is my scenario possible, what should I do?
Requirements:
Solving this by enabling port-forwarding on the router isn't an option
The server has a fixed ip
The client can be disconnected from the internet, at times
The solution has to work on different kinds of routers
Both ports at which packets are send & received are the same
All programming is done in C#
The server notifies the client when there is an update, the client may never poll the server for updates to prevent overload (in case several clients are doing this the same time)
Greets Daan & thanks in advance
EDIT:
Code example from server:
UdpClient udpSender = new UdpClient();
IPEndPoint localServerGateway = new IPEndPoint(IPAddress.Parse(externalIp), 8003);
string message = "testmessage";
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
try
{
udpSender.Send(messageBytes, messageBytes.Length, localServerGateway);
}
catch (Exception error)
{
Console.WriteLine("Error while sending message: " + error.ToString());
}
udpSender.Close();
Code example from client:
private void listenForMasterSyncRequest()
{
bool done = false;
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 8003);
try
{
while (!done)
{
byte[] bytes = masterSyncUdpListener.Receive(ref groupEP);
handleMessage(bytes, bytes.Length, true); // handles incoming messages, this is never reached because no packets are received :-(
}
}
catch (Exception e)
{
Console.WriteLine("An error occured while listening to server broadcast updates: " + e.ToString());
}
finally
{
masterSyncUdpListener.Close();
}
}

NAT works by setting up sessions between external and internal hosts. But the session must be initiated on the internal side, and in your case that's the client side. So the way it has to work is that the client has to poll the server, sending a UDP packet to a particular port on the server asking if a sync is needed. The server must send a UDP response from that same port back to the same port the client sent the original request. If you do it this way packets from the server will get through, otherwise they will not. I know this works because this is exactly how DNS lookups work from behind NAT.

Since you don't have control of the NAT devices in the path, the only sane way here is to use TCP as your main transport.

Related

UDP Server handling multiple remote clients

Lately I've been experimenting with creating a multiplayer game.
In the game each client sends a UDP datagram to the server every time he moves.
Then every X seconds the server sends to all the clients the current state of the game so each client can render all of the other clients.
However when implementing the server I ran into a complication upon receiving datagrams from the clients.
If, lets say, Client A starts sending UDP datagrams to the server and then crashes for whatever reason.
If the server tries to send a message back to the client, since no port is listening on the UDP port on the client's side, his machine will respond with an ICMP packet that contains a ConnectionReset. However, when receiving such packet, I don't have any way through code to know from which remote end point this was received.
Moreover, I've read that the best way to deal with this scenario is simply to close the UDP socket on which this was received (but I obviously don't want to close it, so the server can continue running).
Code to reproduce the scenario:
IPEndPoint serverEndp = new IPEndPoint(IPAddress.Loopback, 8080);
UdpClient server = new UdpClient(serverEndp);
// New client
UdpClient client = new UdpClient();
client.Send(new byte[] { 1, 2, 3 }, 3, serverEndp);
// Simulating that the client has crashed
client.Close();
client.Dispose();
IPEndPoint clientEndPoint = null;
// Server received a datagram from a client which has crashed.
server.Receive(ref clientEndPoint);
// Server doesn't know the client has crashed and tries to send him data back.
server.Send(new byte[] { 4, 5, 6 }, 3, clientEndPoint);
try
{
// The client's machine sends the server an ICMP ConnectionReset datagram.
// When this datagram is received this will throw an exception.
server.Receive(ref clientEndPoint);
}
catch (SocketException se)
{
Console.WriteLine(SocketError.ConnectionReset == se.SocketErrorCode); // True
Console.WriteLine("How to deal with this?");
}
I have several questions:
Should I change my approach to have an extra TCP connection and then determine by that when the client has crashed?
What is the best way to deal with the above scenario?

c# TCP Listener send message to all connected client

Is it possible to send message to all client with tcp listener?
Example:
TCP Listener running, Listener sending the default message to clients, client1 connect get the default message, client2 connect get the default message, if client1 or client2 modify the default message and send it to the listener then listener send the modified message to client1 and client2.
Is it possible to send message to all client with tcp listener?
The answer is NO.
You use a socket server just for wait the new connections (Listener) and accept them. Each time that a socket server accept a new connection it assigns an independent socket client to attend the remote endpoint.
while (keepRunning)
{
try
{
TcpClient socket = server.AcceptTcpClient(); //Socket Server accept a new connection and assigned an independent socket client.
if (keepRunning)
RequestManager.askForRequestAdnRunIt(socket, idLayout); //The Socket Client is attending at the remote endpoint
}
catch (Exception ex)
{
log.Error("Se detecto un error en el puerto para atencion de peticiones. ERR: " + ex.Message);
log.Error(ex.StackTrace);
}
}
So, if you want to send a message to all the TCPClients sockets, you must send it one by one, i suggest send it by a Asynchronous method to improve the performance and avoid bottlenecks. Check this answer of mine to see how to send with asynchronous methods.

Allow client app to automatically connect to server app on same network

I've created two apps (A client and a server) which can communicate with each other as long as I input the local IP address of the machine the server app is running on into the client app (in code).
I would like the client app to automatically discover the local IP address of the machine running the server app and connect to it, so they can be run on any network without the need to enter the IP in code.
Both of these apps with be running on the same network (ie. Over WiFi, not the Internet)
Here is what I have so far in my client app:
// COMMUNICATE WITH SERVER
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.35"), 8888);
public Console()
{
InitializeComponent();
client.Connect(serverEndPoint);
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
In this example I can only connect to a server running on "192.168.2.35", I would like it to be able to find the server running on port 8888 on any machine on the network.
Alternatively, if this isn't possible I would like the server to broadcast its IP as a message (of some sort) and have the client receive this message and verify it is the server and connect to it.
I think my second example is the proper way to do this, but I can't seem to wrap my head around how to get it working (I'm fairly new to C#), and any other examples I've found I can't seem to get to work with my applications.
Here is my server code if it helps answer my question:
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
TcpClient client = this.tcpListener.AcceptTcpClient();
connectedClients++;
lblNumberOfConnections.Text = connectedClients.ToString();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
Thanks
EDIT: I've tried adding THIS to my project, but being so new I'm unsure how to implement it properly, and it didn't get me anywhere.
2nd EDIT: I've tried implementing a UDP broadcast a few times now, with no luck on any attempt yet. My latest attempt was at implementing THIS (minus the chat parts). I just can't seem to get a UDP broadcast working at all with my project, as it seems to be way over my head at my current skill level. Unfortunately, having my client automatically connect to the server is 100% necessary for my project to function...
My other problem, which is maybe best to start a separate question for, but somewhat correlates to this issue is: My client GUI consists of a panel that switches between multiple custom classes, each containing different buttons, etc. (works similar to tab pages) that communicate to the server I'm trying to connect to. Once I get the UDP broadcast figured out, will I need to code that into every class separately? or is there a way of having all classes running in my panel connect to the same server?
A simple, but possibly costly(in terms of network traffic) solution would be for your server application to broadcast over UDP it's application and connection info. Your client could listen for all broadcast packets that have your servers custom header. Assuming a connection is made you could stop the broadcast. The downside is you would have to be broadcasting constantly if a client is not connected and this can clog your network if there aren't limits placed on the broadcast speed.
EDIT: Here is a boiled down explanation generated from the MSDN article https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
EDIT #2: I've expanded on this answer on my blog, as well as provided downloadable example projects. the article can be found at http://martialdeveloper.com/wordpress/?p=21
1. Find your network's broadcast IP
A special “Broadcast Address” must be used when using UDP for the purpose of sending a datagram to all machines connected to a given network. For example, the typical home network host/gateway of 192.168.0.1 has a broadcast address of 192.168.0.255. If your network differs from this you can use an IPv4 broadcast address calculator like the one found here http://jodies.de/ipcalc
Or read the introductory section on MSDN describing the broadcast address. https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
2. Select a listening/broadcast port
Any port that is free on your client & server is fine. The MSDN example uses 11000. This port number is used in your broadcaster, and listener.
3. Code for the Listener
Note to the reader. All error handling has been omitted for clarity of the example.
int listenPort = 11000;
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any,listenPort);
while (!done) // This loop listens for your broadcast packets
{
Console.WriteLine("Waiting for broadcast");
byte[] bytes = listener.Receive( ref groupEP);
Console.WriteLine("Received broadcast from {0} :\n {1}\n",
groupEP.ToString(),
Encoding.ASCII.GetString(bytes,0,bytes.Length));
}
listener.Close();
Note: The third parameter to Console.WriteLine, "Encoding.ASCII..." represents the string value sent over UDP in the datagram packet. This contains the desired negotiation information for a discovery situation, such as the IP address of the client or server you wish to connect to.
4. Code for the Broadcaster
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse("This string should be the broadcast IP address"); //NOTE: Broadcast IP goes here!!
byte[] sendbuf = Encoding.ASCII.GetBytes("This is the message string to be broadcast"); //Your message to the client/server goes here, I.E. an
// app/client name or ID and an IP to connect with over TCP
IPEndPoint ep = new IPEndPoint(broadcast, 11000);
s.SendTo(sendbuf, ep);
Console.WriteLine("Message sent to the broadcast address");
NOTE: This is a very simple example. The broadcaster may need to rebroadcast for a period of time to make sure the Listener receives it. Even after the UDP datagram is sent/received there will need to be some negotiation to ensure the TCP connection is made properly.

Sending a file to a Dynamic port by a TCP Protocol

I am working with an application that receives a file by a TCP protocol, the application processes the file and then sends it by the same protocol, i am receiving the file without problems, my problem is when i try to send the file, because i need to send the file to another application that is listening a Dynamic port, the code that i am using to send these files is:
internal void Send(byte[] buffer)
{
TcpClient _client = null;
try
{
_client = new TcpClient(RemoteIPaddress, Dynamic_port);
if (_client != null)
{
NetworkStream _clienttStream = _client.GetStream();
_clienttStream.Write(buffer, 0, buffer.Length);
_clienttStream.Flush();
_clienttStream.Close();
_clienttStream = null;
}
}
catch
{
if (_client != null)
{
_client.Close();
_client = null;
}
}
}
The question is, how can i send a file by TCP protocol to a remote machine that uses a dynamic port
Typically, the server should listen on a well known port for a connection request. The response should include the port number that the server will communicate further on. Then your app connects to that port for transferring the data.
The communication should do the following:
Client connects to server on well known port.
Server responds with the dynamic port number to use for further communication.
Client connects to server on the received port number.
Server responds stating connection established.
Client transmits data and disconnects.
This is a simplified version of how passive FTP works.
Point is, there are only two ways to connect to a server on a dynamic port. The first way is outlined above. If you can't do it that way then your client app will have to do a port scan, sending a connection attempt to every port within a range, and see which one the server responds on. However, firewalls are generally programmed to notice this type of thing and shut you down (it's hacker behavior).
Are you asking how you can determine the dynamic port that the remote machine has selected to use? There is no automated way to do this. The server should either work on a port that both machines are aware of or you should work out a way for them to select a port through some other mode of communication. Either by connecting to a 3rd party server or hosting a web service that the client can access.

Connecting to own PC using public IP

I'm having a problem with sockets.
I've written myself two simple applications, one server and one client.
The server simply waits for a UDP packet to arrive, printing out something in the console once that happens.
The client sends a UDP packet to a specific end point.
// server
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.Bind(new IPEndPoint(IPAddress.Any, 1337));
IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
byte[] buf = new byte[1024];
sock.ReceiveFrom(buf, ref remote);
Console.WriteLine("Received packet.");
// client
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint remote = new IPEndPoint(IPAddress.Parse(Console.ReadLine()), UInt16.Parse(Console.ReadLine()));
byte[] buf = { 1, 2, 3, 4 }; // random data
sock.SendTo(buf, remote);
Now the weird thing is that when the client socket sends its packet to the public IP address of my router, the server socket only receives it if the client is not run on the same PC as the server. So if I start the server on my PC and then start the client on my PC, enter my public IP and port 1337, the server doesn't receive anything.
However, if I send the client application to my friend and give him my IP address and port, it works perfectly fine.
It also works if I let the client connect to my local IP instead of my public one.
Am I the only one experiencing this behaviour?
Port 1337 is forwarded to the computer the server is ran on, btw.
This seems to be a NAT configuration issue. You must have configured nat on the router to forward packets coming on the public interface with specific port (1337) to be forwarded to the server. So this works when your friend sends you a UDP packet.
But you must not (don't know if its even possible) have configured natting the other way around meaning the same UDP packet coming to the internal interface. This is the case when you send packet from server to client with both on the same machine.
When both the server and client (on a single machine or two different machines) are on your internal network it will be best to use the server's interface id than depending on natting
Most routers and modems do not normally forward UDP traffic -- see http://www.gotroot.com/blogpost4-Why-your-should-never-forward-UDP-out-of-your-firewall for an explanation. Also try attaching both the client and server to the same physical network (well, subnet) and to try sending datagrams directly to the server instead of forwarding them.

Categories