The Info
I have been developing a web http server in c# and decided to add a remote console feature. The console can be used from any location and uses a TcpListener (web server) and a TcpClient (remote console) to send commands and functions through.
The Code
This is what my server looks like:
TcpListener consoleListener = new TcpListener(consolePort);
consoleListener.Start();
byte[] bytes = new Byte[256];
string data = null;
while (true)
{
TcpClient client = consoleListener.AcceptTcpClient();
data = null;
byte[] msg = { 0 };
int i;
while ((i = client.GetStream().Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
if (data == "shutdown")
{
//Server shutdown logic.
}
//Other commands here...
else
{
msg = Encoding.ASCII.GetBytes("Invalid command. Type 'help' or '?' to get a list of commands.");
}
client.GetStream().Write(msg, 0, msg.Length); //sends return message to console
}
client.Close(); //closes connection between client and server after EVERY command. Connection is reopened when a new command is sent.
}
Note - The server is run on a separate thread to both the webserver and main console application thread.
This is my client:
public static string Communicate(string text)
{
try
{
TcpClient client = new TcpClient(ip, port); //initializes tcpclient (ip and port are correct)
byte[] data = System.Text.Encoding.ASCII.GetBytes(text); //converts text to bytes for stream writing
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent data: " + text);
data = new Byte[256];
string responseData = String.Empty; //initializes responsData string
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes
}
catch (Exception ex)
{
return "An error occured\n" + ex.ToString();
}
}
The Problem
I can send one command to the server with a successful return. However, when I try and send another command, the server throws the error below:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at ---.Server.ConsoleListener() in X:\Users\---\Documents\Visual Studio 2013\Projects\---\---\Program.cs:line x
I know it is not firewall or administrator elevation problems as I can send one command through successfully. It is only on the second command sent that it throws this error.
Here is a screenshot describing the problem:
EDIT: By doing a little research, I found that the problem is most likely a result of a small error in my for loop. However, I do not know any way of fixing this as I do not know the exact problem :). Please help me identify it so I can fix it.
Thanks again
It seems that your client closes the connection after one message.
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes
If you want to persist the connection you should have a loop on the client similar to the one you have on the server. If you want to establish a new connection every time you should close the stream gracefully on the server and not have a loop like this. You will still need to loop in case the message is longer or you need to specify max length for the command.