I wrote two small applications (a client and a server) to test UDP communication and I found the 'connection' (yeah, I know, there's no real connection) between them gets lost frecuently for no reason.
I know UDP is an unreliable protocol, but the problem here does not seem the losing of packets, but the losing of the communication channel between the apps.
Here's client app code:
class ClientProgram
{
static void Main(string[] args)
{
var localEP = new IPEndPoint(GetIPAddress(), 0);
Socket sck = new UdpClient(localEP).Client;
sck.Connect(new IPEndPoint(IPAddress.Parse("[SERVER_IP_ADDRESS]"), 10005));
Console.WriteLine("Press any key to request a connection to the server.");
Console.ReadLine();
// This signals the server this clients wishes to receive data
SendData(sck);
while (true)
{
ReceiveData(sck);
}
}
private static void ReceiveData(Socket sck)
{
byte[] buff = new byte[8];
int cnt = sck.Receive(buff);
long ticks = BitConverter.ToInt64(buff, 0);
Console.WriteLine(cnt + " bytes received: " + new DateTime(ticks).TimeOfDay.ToString());
}
private static void SendData(Socket sck)
{
// Just some random data
sck.Send(new byte[] { 99, 99, 99, 99 });
}
private static IPAddress GetIPAddress()
{
IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());
if (he.AddressList.Length == 0)
return null;
return he.AddressList
.Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
.FirstOrDefault();
}
}
Here's the server app code:
class ServerProgram
{
private static int SLEEP = 5;
static void Main(string[] args)
{
// This is a static IP address
var localEP = new IPEndPoint(GetIPAddress(), 10005);
Socket sck = new UdpClient(localEP).Client;
// When this methods returs, a client is ready to receive data
var remoteEP = ReceiveData(sck);
sck.Connect(remoteEP);
while (true)
{
SendData(sck);
System.Threading.Thread.Sleep( ServerProgram.SLEEP * 1000);
}
}
private static EndPoint ReceiveData(Socket sck)
{
byte[] buff = new byte[8];
EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
int cnt = sck.ReceiveFrom(buff, ref clientEP);
Console.WriteLine(cnt + " bytes received from " + clientEP.ToString());
return (IPEndPoint)clientEP;
}
private static void SendData(Socket sck)
{
DateTime n = DateTime.Now;
byte[] b = BitConverter.GetBytes(n.Ticks);
Console.WriteLine("Sending " + b.Length + " bytes : " + n.TimeOfDay.ToString());
sck.Send(b);
}
private static IPAddress GetIPAddress()
{
// Same as client app...
}
}
(this is just test code, don't pay attention to the infinite loops or lack of data validation)
The problem is after a few messages sent, the client stops receiving them. The server keeps sending, but the client gets stuck at sck.Receive(buff). If I change SLEEP constant to a value higher than 5, the 'connection' gets lost after 3 or 4 messages most of the time.
I can confirm the client machine doesn´t receive any packet when the connection is lost since I use Wireshark to monitor the communication.
The server app runs on a server with direct connection to Internet, but the client is a machine in a local network, behind a router. None of them has a firewall running.
Does anyone have a clue what could be happening here?
Thank you!
EDIT - Additional data:
I tested the client app in several machines in the same network and the connection get lost always. I also tested the client app in other network behind other router and there is no problem there. My router is a Linksys RV042 and never had any problem with it, in fact, this app is the only one with problems.
PROBLEM SOLVED - SHORT ANSWER: It was a hardware problem.
I don't see any overt problems in the source code. If it is true that:
The server keeps sending packets (confirmed by WireShark on the server)
The client never receives the packets (confirmed by WireShark on the client)
..then the problem could be related to networking equipment between the two machines, which don't always handle UDP flows as expected especially when behind routers/firewalls.
I would recommend the following approach to troubleshooting:
Run client & server on the same system and use the loopback interface (confirm UDP code works on the loopback)
Run the client & server on two different systems that are plugged into the same Ethernet switch (confirm that UDP communication works switch-local)
If everything works switch-local you can be fairly sure you have a network configuration problem.
Related
Below is my code for the TCP server side. The problem is when the app on client machine closes, the server can't automically try to reconnect every 2 seconds until connected. How can I achieve that?
My idea is after connected to the client, server creates a status thread to send a byte to that client every 30s, if fail ---> terminate connection and retry to connect again. I'm not sure if its gonna work.
public static TcpClient client = new TcpClient();
public static int port = 6446;
public static string connectTo = "192.168.0.11";
public static NetworkStream dataStream;
static void Main(string[] args)
{
int retry = 0;
TryingConnect:
try
{
do
{
if (retry == 10)
{
retry = 0;
Console.Clear();
}
cout("Connecting...");
IPAddress ipAddress = IPAddress.Parse(connectTo);
client.Connect(ipAddress, port);
} while (client.Connected != true);
cout("Connected!");
dataStream = client.GetStream();
}
catch (Exception ex)
{
// Debug: MessageBox.Show(ex.ToString());
retry++;
Thread.Sleep(2000);
goto TryingConnect;
}
}
A server is the communication party which listen for connections from clients. A client is the one which initiates the connection. If you would like to server to recreate a lost connection to the client the server would actually be the client in this case because it initiates a new connection.
Apart from the meaning of the words client and server: if peer C likes S to connect to it C must be first listen and accept incoming connections, which is not the case for the common client. Even if C would do this the network of C must actually be reachable by S to create a new connection. This is often not the case, i.e if C is located in some local network (typical setup at home, work and often on mobile phone) then C is not reachable by S while C itself could reach S. Therefore S could not make a connection back to C.
Alright, so I'm trying to connect to UDP trackers using c#, but I never get a response. I also don't get any errors. Here's my code.
namespace UDPTester
{
class MainClass
{
public static bool messageReceived = false;
public static Random Random = new Random();
public static void LOG(string format, params object[] args)
{
Console.WriteLine (format,args);
}
public static void Main (string[] args)
{
LOG ("Creating Packet...");
byte[] packet;
using(var stream = new MemoryStream())
{
var bc = new MiscUtil.Conversion.BigEndianBitConverter();
using(var br = new MiscUtil.IO.EndianBinaryWriter(bc,stream))
{
LOG ("Magic Num: {0}",(Int64)0x41727101980);
br.Write (0x41727101980);
br.Write((Int32)0);
br.Write ((Int32)Random.Next());
packet = stream.ToArray();
LOG ("Packet Size: {0}",packet.Length);
}
}
LOG ("Connecting to tracker...");
var client = new System.Net.Sockets.UdpClient("tracker.openbittorrent.com",80);
UdpState s = new UdpState();
s.e = client.Client.RemoteEndPoint;
s.u = client;
StartReceiving(s);
LOG ("Sending Packet...");
client.Send(packet,packet.Length);
while(!messageReceived)
{
Thread.Sleep(1000);
}
LOG ("Ended");
}
public static void StartReceiving(UdpState state)
{
state.u.BeginReceive(ReceiveCallback,state);
}
public static void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
Byte[] receiveBytes = u.EndReceive(ar, ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
LOG("Received: {0}", receiveString);
messageReceived = true;
StartReceiving((UdpState)ar.AsyncState);
}
}
public class UdpState
{
public UdpClient u;
public EndPoint e;
}
}
I was using a normal BinaryWriter, but that didn't work, and I read somewhere that it wants it's data in BigEndian.
This doesn't work for any of the UDP trackers I've found, any ideas why I'm not getting a response? Did they maybe change the protocol and not tell anyone? HTTP trackers all work fine.
Trackers I've tried
udp://tracker.publicbt.com:80
udp://tracker.ccc.de:80
udp://tracker.istole.it:80
Also, I'm not interested in using MonoTorrent(and when I was using it, the UDP didn't work anyways).
Protocol Sources
http://xbtt.sourceforge.net/udp_tracker_protocol.html
http://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html
UDP is a connectionless protocol, so you won't see any errors if packets are lost or dropped at the destination.
Try following diagnostic steps:
Use packet sniffer (Wireshark is a good one) to check that UDP packets are leaving the machine.
Install some working BitTorrent client, check if it can communicate with the tracker and if yes, use packet sniffer to see how the packets sent by the working client differ from the packets your code generates.
If working client also can not communicate with the tracker, but the UDP traffic is leaving your machine, the UDP packets are likely dropped by a firewall. You can try 'traceroute' tool to diagnose where your packets are dropped (this is not always 100% reliable, because sometimes firewalls drop UDP packets generated by traceroute and do not drop normal UDP traffic).
I have asked a couple of similar questions the last couple of days and received some really great help. I now understand my problem quite a bit better but I appear to have hit a snag. I have written a client server application that uses both a TCP and UDP connection. The TCP connection works fine over both LAN and WAN but the UDP connection fails over WAN. Based on the questions I asked previously I realized that my server needed to reply to the client at the EndPoint from which it received a communication. I set everything up to work that way. I will post code after the question. My problem is now that while I am using the EndPoint from the client connection and the client is establishing connection first I am still unable to make the UDP connection. It appeared to work over one network but then failed over all the others I have tried. Any help on figuring this out is appreciated. Here is the code.
Receive UDP Messages on the server
private void receiveUDP()
{
System.Net.IPEndPoint test = new System.Net.IPEndPoint(System.Net.IPAddress.Any,UDP_PORT);
System.Net.EndPoint serverIP = (System.Net.EndPoint)test;
trans.Bind(serverIP);
System.Net.IPEndPoint ipep = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
System.Net.EndPoint Remote = (System.Net.EndPoint)ipep;
while (true)
{
byte[] content = new byte[1024];
int recv = trans.ReceiveFrom(content,ref Remote);
int portNum = ((System.Net.IPEndPoint)Remote).Port;
string message = Encoding.ASCII.GetString(content);
string[] data = message.Split((char)124);
//UpdateStatus(data[0] + data[1]);
UserConnection sender = (UserConnection)clients[data[0]];
if (sender.PortNumber != portNum)
sender.PortNumber = portNum;
if (sender.RemoteEnd != Remote)
{
sender.RemoteEnd = Remote;//Stores the EndPoint from the client connection
}
if (data.Length > 2)
{
OnLineRecieved(sender, data[1] + "|" + data[2]);
}
else
{
OnLineRecieved(sender, data[1]);
}
}
}
Client Listens here
private void receiveUDP()
{
System.Net.IPEndPoint test = new System.Net.IPEndPoint(System.Net.IPAddress.Any,UDP_PORT_NUMBER);
System.Net.EndPoint serverIP = (System.Net.EndPoint)test;
server.Bind(serverIP);
server.Ttl = 50;
EndPoint RemoteServ = (EndPoint)servIP;
while (true)
{
byte[] content = new byte[1024];
int data = server.ReceiveFrom(content, ref RemoteServ);
string message = Encoding.ASCII.GetString(content);
result = message;
ProcessCommands(message);
}
}
EDIT: SERVER'S Sending function
public void SendData(string data)
{
if (RemoteEnd != null)//RemoteEnd is refreshed every time the client sends a UDP message
//Each Clients RemoteEnd is stored in a collection of Client objects in a server hashtable
{
//ipep = new IPEndPoint(ipAdd, PortNumber);
byte[] dataArr = Encoding.ASCII.GetBytes(data);
trans.SendTo(dataArr, dataArr.Length, SocketFlags.None, RemoteEnd);
}
}
There could be a lot of things wrong. Remember, UDP doesn't provide transmit pacing, retransmissions, or acknowledgements. So if you need them, you must provide them. If you have the client send first and then wait for responses to each query, your first lost packet will kill the connection.
You also kind of forgot to describe the problem. You say you fail to make the connection, but what does that mean? Does the server receive the client's first packet or not? Does the client receive the server's first reply or not?
You have to determine if this is a programming problem or a network configuration problem.
what I would do is run the client app on the server machine and the server app on the client machine (and switch the hosts they connect to).
If the server app no longer receives UDP messages from the client app, then you have a networking configuration problem.
If the server app can still receive messages from the client app, then you have a programming problem.
I'm going to setup a small client/server server in TCP/IP mode, I use VS2010,C# to develop my apps, I've googled a lot and could find some source codes, but none of them work in internet, I can get some answers in my own local system, i.e. I run my server, then listen for my own localhost (127.0.0.1) then send some data (for example using telnet), it works fine but when I do the same over internet I get nothing! I want to use port 80, as I want to send/receive http data, I have tested several source codes, here is the last code I have used (and it works on localhost with telnet)
//server code:
form_load()
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndpoint = new IPEndPoint(localAddress, 80);
// Bind the socket to the end point
listenSocket.Bind(ipEndpoint);
// Start listening, only allow 1 connection to queue at the same time
listenSocket.Listen(1);
listenSocket.BeginAccept(new AsyncCallback(ReceiveCallback), listenSocket);
Console.WriteLine("Server is waiting on socket {0}", listenSocket.LocalEndPoint);
// Start being important while the world rotates
while (true)
{
Console.WriteLine("Busy Waiting....");
Thread.Sleep(2000);
}
public static void ReceiveCallback(IAsyncResult AsyncCall)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] message = encoding.GetBytes("I am a little busy, come back later!");
Socket listener = (Socket)AsyncCall.AsyncState;
Socket client = listener.EndAccept(AsyncCall);
Console.WriteLine("Received Connection from {0}", client.RemoteEndPoint);
client.Send(message);
Console.WriteLine("Ending the connection");
client.Close();
listener.BeginAccept(new AsyncCallback(ReceiveCallback), listener);
}
send data (client), of course I haven't used this code, is it right?
public static string SendData()
{
TcpClient client = new TcpClient();
client.Connect(IP, 80);
StreamWriter sw = new StreamWriter(client.GetStream());
StreamReader sr = new StreamReader(client.GetStream());
//if statement evalutes to see if the user has selected to update the server
//" " = update server
//"" = do not update the server
//if (updateData.Equals(""))
//{
// space = "";
//}
//else if (!updateData.Equals(""))
//{
// space = " ";
//}
//Refrences stream writer, username variable passed in from GUI
//space variable provides update function: "" = dont update. " " = update database.
sw.WriteLine("h");
sw.Flush();
//data send back from the server assigned to string variable
//string recieved = sr.ReadLine();
return "";
}
I'm going to have the server code in my Server (winserver 2008R2) but currently test it in normal PCs, what am I doing wrong? I want to send some http packet from a random system (with a random IP) to my server (which I know its IP), what should I do? is it possible with tcp/ip or I should do something else?
is it related to static IP? should I certainly have static IP? my web server has a static IP but my clients do not, is it a problem?
I think I have some problem in defining ports and IPs, how should I set them? my server has a specific IP, but I don't know IP of my clients, would you please explain it to me step by step?
thanks
The two most common problems in this scenario:
Ensure your server's router is using port forwarding to forward HTTP requests from the router to the server.
Ensure you are connecting to the server's public IP address, not its local network address.
I'm trying to make a simple C# web server that, at this stage, you can access via your browser and will just do a "Hello World".
The problem I'm having is that the server can receive data fine - I get the browser's header information - but the browser doesn't receive anything I send. Furthermore, I can only connect to the server by going to localhost (or 127.0.0.1). I can't get to it by going to my IP and it's not a network setting because Apache works fine if I run that instead. Also, I'm using a port monitoring program and after I attempt a connection from a browser, the process's port gets stuck in a TIME_WAIT state even though I told the connection to close and it should be back to LISTEN.
Here's the relevant code. A couple calls might not make sense but this is a piece of a larger program.
class ConnectionHandler
{
private Server server;
private TcpListener tcp;
private ArrayList connections;
private bool listening;
private Thread listeningThread;
public Server getServer()
{
return server;
}
private void log(String s, bool e)
{
server.log("Connection Manager: " + s, e);
}
private void threadedListen()
{
while (listening)
{
try
{
TcpClient t = tcp.AcceptTcpClient();
Connection conn = new Connection(this, t);
}
catch (NullReferenceException)
{
log("unable to accept connections!", true);
}
}
log("Stopped listening", false);
}
public void listen()
{
log("Listening for new connections", false);
tcp.Start();
listening = true;
if (listeningThread != null && listeningThread.IsAlive)
{
listeningThread.Abort();
}
listeningThread = new Thread(new ThreadStart(
this.threadedListen));
listeningThread.Start();
}
public void stop()
{
listening = false;
if (listeningThread != null)
{
listeningThread.Abort();
log("Forced stop", false);
}
log("Stopped listening", false);
}
public ConnectionHandler(Server server)
{
this.server = server;
tcp = new TcpListener(new IPEndPoint(
IPAddress.Parse("127.0.0.1"), 80));
connections = new ArrayList();
}
}
class Connection
{
private Socket socket;
private TcpClient tcp;
private ConnectionHandler ch;
public Connection(ConnectionHandler ch, TcpClient t)
{
try
{
this.ch = ch;
this.tcp = t;
ch.getServer().log("new tcp connection to "
+ this.tcp.Client.RemoteEndPoint.ToString(), false);
NetworkStream ns = t.GetStream();
String responseString;
Byte[] response;
Int32 bytes;
responseString = String.Empty;
response = new Byte[512];
bytes = ns.Read(response, 0, response.Length);
responseString =
System.Text.Encoding.ASCII.GetString(response, 0, bytes);
ch.getServer().log("Received: " + responseString);
String msg = "<html>Hello World</html>";
String fullMsg = "HTTP/1.x 200 OK\r\n"
+ "Server: Test Server\r\n"
+ "Content-Type: text/html; "
+ "charset=UTF-8\r\n"
+ "Content-Length: " + msg.Length + "\r\n"
+ "Date: Sun, 10 Aug 2008 22:59:59 GMT"
+ "\r\n";
nsSend(fullMsg, ns);
nsSend(msg, ns);
ns.Close();
tcp.Close();
}
catch (ArgumentNullException e)
{
ch.getServer().log("connection error: argument null exception: " + e);
}
catch (SocketException e)
{
ch.getServer().log("connection error: socket exception: " + e);
}
}
private void nsSend(String s, NetworkStream ns)
{
Byte[] data = System.Text.Encoding.ASCII.GetBytes(s);
ns.Write(data, 0, data.Length);
ns.Flush();
ch.getServer().log("Sent: " + s);
}
}
Does anyone have any ideas? It feels like it's gotta be something stupid on my part but I just don't know what. I'd really appreciate any insight
You might like to know that you can use HttpListener to write a basic web-server very easily - this deals with most of the painful bits, letting you concentrate on writing the actual code. The MSDN page gives an example.
Note that this uses HTTP.SYS, which is good - but means that non-admins need to be explicitly given access to open ports; on xp you can do this with httpcfg; on vista you can use netsh. See here for more.
One thing which isn't a problem at the moment but might be later on is that your content length is based on the Unicode length of the message string, not the binary length.
There's also rather a lot going on in the Connection constructor - stuff that really doesn't belong in a constructor at all, IMO. It also doesn't close things if exceptions occur.
Have you looked at what's going on in a network tracer like WireShark? That would be the easiest way of seeing whether any data is getting sent back to the client.
Alternatively, post a short but complete version of your code which we can compile and run ourselves.
Maybe I'm just missing something but the reason you can only connect on localhost is because the IP you are listening on is 127.0.0.1, this makes the TCPListener only listen on that IP address. And I don't see anywhere you are calling any client disconnect, the TCPListener is a blocking call, so it sits there forever until a connection is made. In my past experience with TCP/IP and the TCPListener, TCPClient classes there is not much of a way to force the listener to drop it's connection until you drop the client connection. Calling TCPListener.Abort() doesn't drop the client connection which keeps the port blocked up.
For anyone in similar situation where you want to access you C# server from the local network ip address then you will need to listen to address 0.0.0.0 meaning listen on all ip addresses not a specific one like 127.0.0.1 etc.