TcpClient - An existing connection was forcibly closed by the remote host

51,528

Solution 1

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.

Solution 2

I don't know if you fixed your issue or not but I guess you should post your workaround at least so others can check it.

I don't fully understand your issue but I had the same exception, but mine was triggered while the client disconnected and server was trying to read the stream (networkStream).

I had a single command for reading

networkstream.Read(mybuffer, 0, mybuffer.length);

As the checked answer suggested I changed that for:

do
{
 byte[] buff = new byte[1];
 networkstream.Read(buff, 0, 1);
 myreceivedbuff.Add(buff);
} while (networkstream.DataAvailable)

this also produced the issue while client disc, so I had to do this

do
{
 byte[] buff = new byte[1];
 try
 {
  networkstream.Read(buff, 0, 1);
 }
 catch(exception ex)
 {
  throw new exception("The dam client disconnected in the middle of a transaction.");
 }
 myreceivedbuff.Add(buff);
} while (networksteam.DataAvailable)

I had to do this since it doesn't matter if its on a client or a server the exception is the same. host disconnection meanwhile my exception was CLIENT disconnection and this generic message misguided me to the solution.

Sorry if the code is not pasted from vs but I typed here so fix the capitalization so it can compile.

Hope this helps someone.

Share:
51,528
rodit
Author by

rodit

Updated on July 20, 2020

Comments

  • rodit
    rodit almost 4 years

    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: The remote console and server communication and error reporting.

    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

  • rodit
    rodit almost 10 years
    Thanks for the help. Although this didn't solve my problem, you made me mess up my code enough to realise I had to do it a different way :) so thanks anyway! You, as a result of that, get a big green tick!
  • Kenny Evitt
    Kenny Evitt about 9 years
    @rodit a "green tick" (accepting an answer) shouldn't be a reward for someone that helped you if they didn't also the answer the question you asked.
  • Emil
    Emil over 5 years
    why did you use do while instead of while? first request may fail as well, not?