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.
Related
I am working on HoloLens (Unity-UWP) and trying to make a connection with PC (UWP) or Android phone work (Xamarin). So far I tried client and host with both Bluetooth and TCP (even two versions with different libraries) on Android and UWP. I kept the code entirely separated from user interface, so that it is easier to use, to understand and modular. An Action<string> is used to output results (error logs and sent messages).
Everything that is not on the HoloLens works fine (even though it's exactly the same code). It worked from PC (UWP) to Android with client and host switched. But it doesn't even work between HoloLens and PC (UWP). The behavior ranged from crashes (mostly for Bluetooth) to instant disconnection. The last tests resulted in disconnection once bytes are about to be received. It could even read the first 4 bytes (uint for the length of the following UTF-8 message), but then it was disconnected. The other devices seemed to work fine.
What I know: Capabilities are set, the code works, the issue is likely something that is common for everything that has to do with networking and HoloLens.
So the question is, is Unity or HoloLens incompatible with something I am using? What I used which is worth mentioning: StreamSocket, BinaryWriter, BinaryReader, Task (async, await). Or is HoloLens actively blocking communication with applications on other devices? I know it can connect to devices with Bluetooth and that it can connect via TCP, and it looks like people succeed to get it to work. Are there known issues? Or is there something with Unity that causes this - a bad setting maybe? Do I have to use async methods or only sync? Are there incompatibility issues with Tasks/Threads and Unity? Is this possibly the issue (inability to consent to permissions)?
Another thing to note is that I cannot ping HoloLens via its IP by using the cmd, even though the IP is correct.
I'd appreciate any advice, answer or guess. I can provide more information if requested (see also the comments below). I would suggest to focus on the TCP connection as it seemed to be working better and appears to be more "basic." Here is the code:
using System;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Networking;
using Windows.Networking.Sockets;
#region Common
public abstract class TcpCore
{
protected StreamSocket Socket;
protected BinaryWriter BWriter;
protected BinaryReader BReader;
protected Task ReadingTask;
public bool DetailedInfos { get; set; } = false;
public bool Listening { get; protected set; }
public ActionSingle<string> MessageOutput { get; protected set; } = new ActionSingle<string> (); // Used for message and debug output. They wrap an Action and allow safer use.
public ActionSingle<string> LogOutput { get; protected set; } = new ActionSingle<string> ();
protected const string USED_PORT = "1337";
protected readonly Encoding USED_ENCODING = Encoding.UTF8;
public abstract void Disconnect ();
protected void StartCommunication ()
{
Stream streamOut = Socket.OutputStream.AsStreamForWrite ();
Stream streamIn = Socket.InputStream.AsStreamForRead ();
BWriter = new BinaryWriter (streamOut); //{ AutoFlush = true };
BReader = new BinaryReader (streamIn);
LogOutput.Trigger ("Connection established.");
ReadingTask = new Task (() => StartReading ());
ReadingTask.Start ();
}
public void SendMessage (string message)
{
// There's no need to send a zero length message.
if (string.IsNullOrEmpty (message)) return;
// Make sure that the connection is still up and there is a message to send.
if (Socket == null || BWriter == null) { LogOutput.Trigger ("Cannot send message: No clients connected."); return; }
uint length = (uint) message.Length;
byte[] countBuffer = BitConverter.GetBytes (length);
byte[] buffer = USED_ENCODING.GetBytes (message);
if (DetailedInfos) LogOutput.Trigger ("Sending: " + message);
BWriter.Write (countBuffer);
BWriter.Write (buffer);
BWriter.Flush ();
}
protected void StartReading ()
{
if (DetailedInfos) LogOutput.Trigger ("Starting to listen for input.");
Listening = true;
while (Listening)
{
try
{
if (DetailedInfos) LogOutput.Trigger ("Starting a listen iteration.");
// Based on the protocol we've defined, the first uint is the size of the message. [UInt (4)] + [Message (1*n)] - The UInt describes the length of the message (=n).
uint length = BReader.ReadUInt32 ();
if (DetailedInfos) LogOutput.Trigger ("ReadLength: " + length.ToString ());
MessageOutput.Trigger ("A");
byte[] messageBuffer = BReader.ReadBytes ((int) length);
MessageOutput.Trigger ("B");
string message = USED_ENCODING.GetString (messageBuffer);
MessageOutput.Trigger ("Received Message: " + message);
}
catch (Exception e)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus (e.HResult) == SocketErrorStatus.Unknown)
{
// Seems to occur on disconnects. Let's not throw().
Listening = false;
Disconnect ();
LogOutput.Trigger ("Unknown error occurred: " + e.Message);
break;
}
else
{
Listening = false;
Disconnect ();
break;
}
}
}
LogOutput.Trigger ("Stopped to listen for input.");
}
}
#endregion
#region Client
public class GTcpClient : TcpCore
{
public async void Connect (string target, string port = USED_PORT) // Target is IP address.
{
try
{
Socket = new StreamSocket ();
HostName serverHost = new HostName (target);
await Socket.ConnectAsync (serverHost, port);
LogOutput.Trigger ("Connection successful to: " + target + ":" + port);
StartCommunication ();
}
catch (Exception e)
{
LogOutput.Trigger ("Connection error: " + e.Message);
}
}
public override void Disconnect ()
{
Listening = false;
if (BWriter != null) { BWriter.Dispose (); BWriter.Dispose (); BWriter = null; }
if (BReader != null) { BReader.Dispose (); BReader.Dispose (); BReader = null; }
if (Socket != null) { Socket.Dispose (); Socket = null; }
if (ReadingTask != null) { ReadingTask = null; }
}
}
#endregion
#region Server
public class GTcpServer : TcpCore
{
private StreamSocketListener socketListener;
public bool AutoResponse { get; set; } = false;
public async void StartServer ()
{
try
{
//Create a StreamSocketListener to start listening for TCP connections.
socketListener = new StreamSocketListener ();
//Hook up an event handler to call when connections are received.
socketListener.ConnectionReceived += ConnectionReceived;
//Start listening for incoming TCP connections on the specified port. You can specify any port that's not currently in use.
await socketListener.BindServiceNameAsync (USED_PORT);
}
catch (Exception e)
{
LogOutput.Trigger ("Connection error: " + e.Message);
}
}
private void ConnectionReceived (StreamSocketListener listener, StreamSocketListenerConnectionReceivedEventArgs args)
{
try
{
listener.Dispose ();
Socket = args.Socket;
if (DetailedInfos) LogOutput.Trigger ("Connection received from: " + Socket.Information.RemoteAddress + ":" + Socket.Information.RemotePort);
StartCommunication ();
}
catch (Exception e)
{
LogOutput.Trigger ("Connection Received error: " + e.Message);
}
}
public override void Disconnect ()
{
Listening = false;
if (socketListener != null) { socketListener.Dispose (); socketListener = null; }
if (BWriter != null) { BWriter.Dispose (); BWriter.Dispose (); BWriter = null; }
if (BReader != null) { BReader.Dispose (); BReader.Dispose (); BReader = null; }
if (Socket != null) { Socket.Dispose (); Socket = null; }
if (ReadingTask != null) { ReadingTask = null; }
}
}
#endregion
Coincidentially, I just implemented a BT connection between HoloLens and an UWP app. I followed the sample at https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothRfcommChat.
As capabilities, I set "Bluetooth" (of course), "Internet (Client & Server)" and "Private Networks (Client & Server)". The steps on the server side then are:
Create an RfcommServiceProvider for your own or an existing (eg OBEX object push) service ID.
Create a StreamSocketListener and wire its ConnectionReceived Event.
Bind the service Name on the listener: listener.BindServiceNameAsync(provider.ServiceId.AsString(), SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
If you have a custom service ID, set its name along with other attributes you may want to configure. See the sample linked above for this. I think, this is mostly optional.
Start advertising the BT service: provider.StartAdvertising(listener, true);
Once a client connects, there is a StreamSocket in the StreamSocketListenerConnectionReceivedEventArgs that you can use to create a DataReader and DataWriter on like on any other stream. If you only want to allow one client, you can also stop advertising now.
On the client side, you would:
Show the DevicePicker and let the user select the peer device. Do not forget setting a filter like picker.Filter.SupportedDeviceSelectors.Add(BluetoothDevice.GetDeviceSelectorFromPairingState(true)); You can also allow unpaired devices, but you need to call PairAsync before you can continue in step 2. Also, I think there is no way to circumvent the user consent dialogue in this case, so I would recommend pairing before. To be honest, I did not check whether the unpaired stuff works on HoloLens.
You get a DeviceInformation instance from the picker, which you can use to obtain a BT device like await BluetoothDevice.FromIdAsync(info.Id);
Get the services from the device like device.GetRfcommServicesAsync(BluetoothCacheMode.Uncached); and select the one you are interested in. Note that I found that the built-in filtering did not behave as expected, so I just enumerated the result and compared the UUIDs manually. I believe that the UWP implementation performs a case-sensitive string comparison at some point, which might lead to the requested service not showing up although it is there.
Once you found your service, which I will call s from now on, create a StreamSocket and connect using socket.ConnectAsync(s.ConnectionHostName, s.ConnectionServiceName, SocketProtectionLevel.PlainSocket);
Again, you can not create the stream readers and writers like on the server side.
The answer is Threading.
For whoever may have similar issues, I found the solution. It was due to Unity itself, not HoloLens specifically. My issue was that I wrote my code separately in an own class instead of commingle it with UI code, which would have made it 1. unreadable and 2. not modular to use. So I tried a better coding approach (in my opinion). Everybody could download it and easily integrate it and have basic code for text messaging. While this was no issue for Xamarin and UWP, it was an issue for Unity itself (and there the Unity-UWP solution as well).
The receiving end of Bluetooth and TCP seemed to create an own thread (maybe even something else, but I didn't do it actively), which was unable to write on the main thread in Unity, which solely handles GameObjects (like the output log). Thus I got weird log outputs when I tested it on HoloLens.
I created a new TCP code which works for Unity but not the Unity-UWP solution, using TcpClient/TcpListener, in order to try another version with TCP connection. Luckily when I ran that in the editor it finally pointed on the issue itself: The main thread could not be accessed, which would have written into the UI - the text box for the log output. In order to solve that, I just had to use Unity's Update() method in order to set the text to the output. The variables themselves still could be accessed, but not the GameObjects.
Pre:
Client open socket to send data to the server:
private void Form1_Load(object sender, EventArgs e)
{
client = new TcpClient();
client.BeginConnect("127.0.0.1", 995, new AsyncCallback(ConnectCallback), client);
}
private void ConnectCallback(IAsyncResult _result) // it will send hello message from client
{
string data;
byte[] remdata = { };
IAsyncResult inResult = _result;
currentProcess = Process.GetCurrentProcess();
string currentProcessAsText = currentProcess.Id.ToString();
SetControlPropertyThreadSafe(proccessIdLabel, "Text", currentProcessAsText);
try {
sock = client.Client;
// send hello message
data = "Client with proccess id " + currentProcessAsText + " is connecting";
sock.Send(Encoding.ASCII.GetBytes(data));
SetControlPropertyThreadSafe(answersTextBox, "Text", answersTextBox.Text + "\n"+ GetCurrentTime() + " Connection established");
}
catch
{
SetControlPropertyThreadSafe(answersTextBox, "Text", answersTextBox.Text + "\n" + GetCurrentTime() + " Can't connect");
}
}
After that I have handler for click on some button (to send messages):
private void SendButton_Click(object sender, EventArgs e)
{
try
{
string data;
sock = client.Client;
data = "Some text";
sock.Send(Encoding.ASCII.GetBytes(data));
}
catch
{
SetControlPropertyThreadSafe(answersTextBox, "Text", "Can't connect");
}
}
Also handler for form close to send server exit command, so he will stop thread for this client:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
sock.Send(Encoding.ASCII.GetBytes("exit"));
sock.Close();
}
catch
{
}
}
Server listening port and handles messages:
private void Listeners()
{
Socket socketForClient = Listener.AcceptSocket();
string data;
int i = 0;
if (socketForClient.Connected)
{
string remoteHost = socketForClient.RemoteEndPoint.ToString();
Console.WriteLine(Message("Client:" + remoteHost + " now connected to server."));
while (true)
{
// буфер данных
byte[] buf = new byte[1024];
try
{
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
byte[] cldata = new byte[messageLength];
socketForClient.Receive(cldata);
data = "";
data = Encoding.ASCII.GetString(cldata).Trim();
if (data.Contains("exit"))
{
socketForClient.Close();
string message = Message("Client:" + remoteHost + " is disconnected from the server (client wish).");
Console.WriteLine(message);
return;
}
else
{
Console.WriteLine(Message("Recevied message from client " + remoteHost + ":\n"));
Console.WriteLine(data);
Console.WriteLine("\nEOF\n");
}
}
}
catch
{
string message = Message("Client:" + remoteHost + " is disconnected from the server (forced close).");
Console.WriteLine(message);
socketForClient.Close();
return;
}
}
}
}
private void ServStart()
{
Listener = new TcpListener(LocalPort);
Listener.Start(); // начали слушать
Console.WriteLine("Waiting connections [" + Convert.ToString(LocalPort) + "]...");
for (int i = 0; i < 1000; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
}
So on server start it creates 1000 threads, which are listens clients messages.
Problems:
I will describe some situation:
Start server
Server starts threads and ready to accept clients connections
Start client
Connection is establishing. Server says that client connected on some port. Client send "hello" message. Server doesn't handle this hello message.
Push the button, so client will send Some text to the server. Server handles this message.
Push the button. Client sends "some text" again. Server doesn't handles that message.
Push the button. Client sends "some text" again. Server handles that message.
If I will push again, it will not handle it obviously....
Server logs:
Why server receives/client sends only 1 of 2 messages? What can cause it?
Also I have problems with sending exit message to the server, when client form is closing. I send exit message on this action.
So situation:
I just pushed the button and server handled it (so server will not handle next message).
I close the form, message is sended, but either client sends wrong message or server receives wrong message.
Situation in console:
You can see, that when form was closed and client sended exit, server handled empty message. Why?
Situation when client exit command passed by server normally:
.....
Client sends data, server doesn't handled it
Now, server will handle client, so we try to close form:
Console:
So in 2nd item client had sended hello message and server failed to handle it. In 3rd item client sends exit command and server passed it correctly.
Main question: why server handles only 1 of 2 messages from client?
Another point: also I found, that when client send exit data, server receives exit\0\0\0\0\0\0\0\0\ (or more, or less \0 symbols). Why?
Good news I think, that server receives or not receives messages constantly. 1 message is received, 1 message is not. That says about my lack of knowledges, but not random error.
So many bugs. :(
That said, the biggest one I noticed was this one:
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
byte[] cldata = new byte[messageLength];
socketForClient.Receive(cldata);
data = "";
data = Encoding.ASCII.GetString(cldata).Trim();
First, understand that in TCP, you have no guarantees about the number of bytes any given receive operation will receive. No matter how the remote endpoint sends the data, you could receive all of the data at once, or only parts of it, in separate receive operations. TCP guarantees the bytes will be received in the same order in which they were sent, and nothing more.
But the above code not only fails to take that into account, it's just completely wrong. The number of bytes received in the first operation is how many bytes were received in that operation. But you are using that number as if it would tell you something about the number of bytes received in the next call to Receive(). It does nothing of the sort. At the same time, you ignore the data you received in the first operation.
Instead, your code should look more like this:
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
data = Encoding.ASCII.GetString(buf, 0, messageLength).Trim();
That's still not quite right, because of course you could receive just a partial message in the call to Receive(), or even more than one message concatenated together. But at least you're likely to see all of the text.
That change will address the specific question you've asked about. If you have trouble figuring out how to address the other bugs, please feel free to post concise, specific questions and code examples to ask for help on those. See https://stackoverflow.com/help/mcve and https://stackoverflow.com/help/how-to-ask for advice on better ways to present your question.
I'm developing a Windows Phone application that will connect to my server. It does this by using ConnectAsync when you push the login button. But if the server is down and you want to cancel the connecting attempt, what to do?
Here is is the current client code complete with my latest try at shutting the socket connection down. It is to be assumed that you can easily implement a timeout once you know how to turn the connection off.
private IPAddress ServerAddress = new IPAddress(0xff00ff00); //Censored my IP
private int ServerPort = 13000;
private Socket CurrentSocket;
private SocketAsyncEventArgs CurrentSocketEventArgs;
private bool Connecting = false;
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
if (Connecting)
{
CurrentSocket.Close();
CurrentSocket.Dispose();
CurrentSocketEventArgs.Dispose();
CurrentSocket = null;
CurrentSocketEventArgs = null;
}
UserData userdata = new UserData();
userdata.Username = usernameBox.Text;
userdata.Password = passwordBox.Password;
Connecting = ConnectToServer(userdata);
}
catch (Exception exception)
{
Dispatcher.BeginInvoke(() => MessageBox.Show("Error: " + exception.Message));
}
}
private bool ConnectToServer(UserData userdata)
{
CurrentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Create a new SocketAsyncEventArgs
CurrentSocketEventArgs = new SocketAsyncEventArgs();
CurrentSocketEventArgs.RemoteEndPoint = new IPEndPoint(ServerAddress, ServerPort);
CurrentSocketEventArgs.Completed += ConnectionCompleted;
CurrentSocketEventArgs.UserToken = userdata;
CurrentSocketEventArgs.SetBuffer(new byte[1024], 0, 1024);
CurrentSocket.ConnectAsync(CurrentSocketEventArgs);
return true;
}
Edit: A thought that struck me is that perhaps it's the server computer that stacks up on requests even though the server software isn't on? Is that possible?
I believe
socket.Close()
should cancel the async connection attempt. There may be some exceptions that need to be caught as a consequence.
Your code looks OK.
As already said by Marc, closing the socket cancels all pending operations.
Yes, it's sometimes possible that you connect OK and nothing happens. To verify, in the command line
telnet 192.168.1.44 31337 where 192.168.1.44 is ServerAddress (name is OK as well) and 31337 is ServerPort. You might first enable a "Telnet client" using Control Panel/Programs and Features/Turn Windows features on and off. If you see "Could not open connection" = your WinForms application shouldn't be able to connect. If you see a black screen with blinking cursor = your WinForms application should connect OK.
What's going on here is that you are specifying a buffer in the argument to ConnectAsync.
CurrentSocketEventArgs.SetBuffer(new byte[1024], 0, 1024);
The documentation says:
Optionally, a buffer may be provided which will atomically be sent on the socket after the ConnectAsync method succeeds.
So your server is going to see the connection and data at once. Your cancellation code is just fine, it's just that the data is sent before you get a chance to cancel anything.
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.
I am connecting to a remote server in C# via a socket and sending data across, upon disconnect I try to re-establish the connection by creating a new socket and reinitialising it.
This works for me when I test by pulling out the ethernet cable and reconnecting it a few mins later, but occasionally (every few hours maybe) I get the one of two exceptions while connected and cannot reconnect...
System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
.......
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
If I restart the application everything works fine once again, so im curious as to why creating a new socket doesnt work. Am I missing an initialisation somewhere perhaps? Any ideas? I use the same method for connection each time:
public static bool OpenConnection(string siteName)
{
bool success;
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(serverIp), Convert.ToInt16(serverRemotePort));
try
{
client = null;
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("Try to connect to the server ..." + ip.Address.ToString());
client.Connect(ip);
Console.WriteLine("Connection established");
//Send the nameSite first
string nameSite = EncryptString(siteName, pwd, initVector) + "*";
byte[] dataSite = new byte[100];
dataSite = Encoding.ASCII.GetBytes(nameSite);
client.Send(dataSite, dataSite.Length, SocketFlags.None);
Console.WriteLine("NameSite send");
success = true;
}
catch (SocketException e)
{
success = false;
Console.WriteLine("Unable to connect to the server : " + e.StackTrace);
}
return success;
}
I try to reconnect as follows in the catch, count is incrementing with each iteration of a while loop.
if (count % 20 == 0)
{
try
{
if (OpenConnection(siteName))
connected = true;
EventLog.WriteEntry("Connection re-established.");
}
catch (SocketException socketEx)
{
Console.WriteLine("Reconnection failed. Storing data locally. \n\n " + socketEx);
EventLog.WriteEntry("Reconnection failed. Storing data locally. \n\n " + socketEx);
}
}
The constructor simply initialises the IP and Port No. Why is it that certain types of disconnect prevent me from reconnecting without a restart, any ideas?
Do you ever call Dispose() on client to clean it up?
Try adding the call to Dispose() before you null out the client in your OpenConnection method
client.Dispose();
client = null;
After looking at the documentation for Socket on the MSDN, the Disconnect method seems like it also might solve your problem. However, I'm not sure where in your code it should go since the question shows a portion of the logic.