TcpClient - 远程主机强制关闭现有连接

时间:2014-07-15 20:05:07

标签: c# tcpclient tcplistener

信息

我一直在用c#开发一个web http服务器,并决定添加一个远程控制台功能。控制台可以在任何位置使用,并使用TcpListener(Web服务器)和TcpClient(远程控制台)来发送命令和功能。

守则

这就是我的服务器的样子:

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.
}

注 - 服务器在与Web服务器和主控制台应用程序线程分开的线程上运行。

这是我的客户:

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();
    }
}

问题

我可以通过成功返回向服务器发送一个命令。但是,当我尝试发送另一个命令时,服务器会抛出以下错误:

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

我知道这不是防火墙或管理员提升问题,因为我可以成功发送一个命令。只有在发送的第二个命令上才会抛出此错误。

以下是描述问题的屏幕截图: The remote console and server communication and error reporting.

编辑:通过一些研究,我发现问题很可能是我的for循环中出现小错误的结果。但是,我不知道如何解决这个问题,因为我不知道确切的问题:)。请帮我识别一下,以便我可以解决它。

再次感谢

3 个答案:

答案 0 :(得分:4)

您的客户似乎在一条消息后关闭了连接。

responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes

如果你想要保持连接,你应该在客户端上有一个类似于你在服务器上的循环。如果您希望每次在服务器上优雅地关闭流时建立新连接,而不是像这样的循环。如果消息较长或者您需要指定命令的最大长度,您仍需要循环。

答案 1 :(得分:4)

我不知道您是否修复了您的问题,但我想您应该至少发布您的解决方法,以便其他人可以检查。

我没有完全理解您的问题,但我遇到了同样的异常,但是在客户端断开连接且服务器尝试读取流(networkStream)时触发了我的。

我只有一个阅读命令

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

如检查答案所示我改为:

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

这也产生了客户端光盘的问题,所以我不得不这样做

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)

我必须这样做,因为如果它在客户端或服务器上的异常是相同的并不重要。主机断开连接,同时我的例外是客户端断开连接,这个通用消息误导我解决方案。

很抱歉,如果代码没有从vs粘贴,但是我输入了这里,所以修复大写以便它可以编译。

希望这有助于某人。

答案 2 :(得分:0)

我有相同的解决方案。如果客户端断开连接,通常会发生这种情况。很遗憾,Alex RG的解决方案无法正常工作。您将获得另一个例外。最佳解决方案由Microsoft here描述

您需要使用CanRead

进行检查
TcpClient tcpClient = new TcpClient ();

// Uses the GetStream public method to return the NetworkStream.
NetworkStream netStream = tcpClient.GetStream ();

if (netStream.CanRead)
{
    // Reads NetworkStream into a byte buffer.
    byte[] bytes = new byte[tcpClient.ReceiveBufferSize];

    // Read can return anything from 0 to numBytesToRead. 
    // This method blocks until at least one byte is read.
    netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);

    // Returns the data received from the host to the console.
    string returndata = Encoding.UTF8.GetString (bytes);

    Console.WriteLine ("This is what the host returned to you: " + returndata);

}
else
{
    Console.WriteLine ("You cannot read data from this stream.");
    tcpClient.Close ();

    // Closing the tcpClient instance does not close the network stream.
    netStream.Close ();
    return;
}