信息
我一直在用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
我知道这不是防火墙或管理员提升问题,因为我可以成功发送一个命令。只有在发送的第二个命令上才会抛出此错误。
以下是描述问题的屏幕截图:
编辑:通过一些研究,我发现问题很可能是我的for循环中出现小错误的结果。但是,我不知道如何解决这个问题,因为我不知道确切的问题:)。请帮我识别一下,以便我可以解决它。再次感谢
答案 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;
}