私はこれに苦労していて、私のコードが私も書いたTCPサーバーから正しく読み取れない理由を見つけることができません。TcpClient
クラスとそのGetStream()
メソッドを使用していますが、期待どおりに機能していません。操作が無期限にブロックされるか(最後の読み取り操作が期待どおりにタイムアウトしない)、またはデータがトリミングされます(何らかの理由で、読み取り操作が0を返し、ループを終了します。サーバーが十分な速度で応答していない可能性があります)。この機能を実装するための3つの試みは次のとおりです。
// this will break from the loop without getting the entire 4804 bytes from the server
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// this will block forever. It reads everything but freezes when data is exhausted
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// inserting a sleep inside the loop will make everything work perfectly
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
Thread.Sleep(20);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
最後のものは「機能」しますが、ソケットがすでに読み取りタイムアウトをサポートしていることを考えると、ハードコードされたスリープをループ内に置くのは確かに醜いようです。のにいくつかのプロパティを設定する必要がありますTcpClient
かNetworkStream
?問題はサーバーにありますか?サーバーは接続を閉じません。閉じるのはクライアント次第です。上記はUIスレッドコンテキスト(テストプログラム)内でも実行されていますが、おそらくそれと関係があります...
誰かが、NetworkStream.Read
データが利用できなくなるまでデータを読み取るために適切に使用する方法を知っていますか?私が望んでいるのは、古いWin32 winsockタイムアウトプロパティのようなものだと思います...ReadTimeout
など。タイムアウトに達するまで読み取ろうとし、その後0を返します...しかし、データが必要なときに0を返すように見えることがあります。利用可能である(または途中で..利用可能な場合はReadが0を返すことができますか?)そして、データが利用できない場合、最後の読み取りで無期限にブロックします。
はい、途方に暮れています!