情報
私は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();
}
}
問題
サーバーに1つのコマンドを送信して、正常に戻ることができます。ただし、別のコマンドを送信しようとすると、サーバーは次のエラーをスローします。
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
1つのコマンドを正常に送信できるため、ファイアウォールや管理者の昇格の問題ではないことがわかります。このエラーをスローするのは、送信された2番目のコマンドのみです。
問題を説明するスクリーンショットは次のとおりです。
編集:少し調べてみると、問題はforループの小さなエラーの結果である可能性が高いことがわかりました。ただし、正確な問題がわからないため、これを修正する方法がわかりません:)。修正できるように、特定するのを手伝ってください。
再度、感謝します
1つのメッセージの後で、クライアントが接続を閉じているようです。
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes
接続を維持したい場合は、サーバー上にあるのと同様のループをクライアント上に持つ必要があります。毎回新しい接続を確立したい場合は、サーブでストリームを正常に閉じ、このようなループを持たないようにする必要があります。メッセージが長い場合や、コマンドの最大長を指定する必要がある場合は、ループする必要があります。
問題を修正したかどうかはわかりませんが、少なくとも他の人が確認できるように、回避策を投稿する必要があると思います。
私はあなたの問題を完全には理解していませんが、同じ例外がありましたが、クライアントが切断され、サーバーがストリーム(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から貼り付けられていない場合は申し訳ありませんが、ここに入力したので、大文字と小文字を修正してコンパイルできるようにします。
これが誰かを助けることを願っています。
私は同じ解決策を持っていました。これは通常、クライアントが切断された場合に発生します。 Alex RGのソリューションは、残念ながら機能していません。別の例外が発生します。最良の解決策が説明されています ここ マイクロソフト
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;
}