下記コードでTcpClientで得られたNetworkStreamをStreamReader/Writerで読み書きしようとしたのですが,ReadToEndの部分でずっと止まってしまいます.原因は何でしょうか.
C#
1using System; 2using System.Collections.Generic; 3using System.IO; 4using System.Linq; 5using System.Net.Sockets; 6using System.Text; 7using System.Threading.Tasks; 8 9namespace ConsoleApp6 10{ 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 var client = new TcpClient(); 16 client.Connect("www.google.co.jp", 80); 17 18 var stream = client.GetStream(); 19 var sw = new StreamWriter(stream); 20 sw.Write("GET http://www.google.co.jp/ HTTP/1.1\r\nHost:www.google.co.jp\r\n\r\n"); 21 22 var sr = new StreamReader(stream); 23 var res = sr.ReadToEnd(); 24 Console.WriteLine(res); 25 26 Console.Read(); 27 } 28 } 29}
このようにした場合はReadの部分で止まってしまいます.
C#
1using System; 2using System.Collections.Generic; 3using System.IO; 4using System.Linq; 5using System.Net.Sockets; 6using System.Text; 7using System.Threading.Tasks; 8 9namespace ConsoleApp6 10{ 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 var client = new TcpClient(); 16 client.Connect("www.google.co.jp", 80); 17 18 var stream = client.GetStream(); 19 var sw = new StreamWriter(stream); 20 sw.Write("GET http://www.google.co.jp/ HTTP/1.1\r\nHost:www.google.co.jp\r\n\r\n"); 21 22 var ms = new MemoryStream(); 23 var resBytes = new byte[256]; 24 var resSize = 0; 25 do 26 { 27 //データの一部を受信する 28 resSize = stream.Read(resBytes, 0, resBytes.Length); 29 //Readが0を返した時はサーバーが切断したと判断 30 if (resSize == 0) 31 { 32 Console.WriteLine("サーバーが切断しました。"); 33 break; 34 } 35 //受信したデータを蓄積する 36 ms.Write(resBytes, 0, resSize); 37 //まだ読み取れるデータがあるか、データの最後が\nでない時は、 38 // 受信を続ける 39 } while (stream.DataAvailable || resBytes[resSize - 1] != '\n'); 40 //受信したデータを文字列に変換 41 string resMsg = Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length); 42 ms.Close(); 43 //末尾の\nを削除 44 resMsg = resMsg.TrimEnd('\n'); 45 Console.WriteLine(resMsg); 46 47 Console.Read(); 48 } 49 } 50}
送信部もStreamWriterを使わずにこうすると成功します.
C#
1using System; 2using System.Collections.Generic; 3using System.IO; 4using System.Linq; 5using System.Net.Sockets; 6using System.Text; 7using System.Threading.Tasks; 8 9namespace ConsoleApp6 10{ 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 var client = new TcpClient(); 16 client.Connect("www.google.co.jp", 80); 17 18 var stream = client.GetStream(); 19 20 var sendBytes = Encoding.UTF8.GetBytes("GET http://www.google.co.jp/ HTTP/1.1\r\nHost:www.google.co.jp\r\n\r\n" + '\n'); 21 stream.Write(sendBytes, 0, sendBytes.Length); 22 23 var ms = new MemoryStream(); 24 var resBytes = new byte[256]; 25 var resSize = 0; 26 do 27 { 28 //データの一部を受信する 29 resSize = stream.Read(resBytes, 0, resBytes.Length); 30 //Readが0を返した時はサーバーが切断したと判断 31 if (resSize == 0) 32 { 33 Console.WriteLine("サーバーが切断しました。"); 34 break; 35 } 36 //受信したデータを蓄積する 37 ms.Write(resBytes, 0, resSize); 38 //まだ読み取れるデータがあるか、データの最後が\nでない時は、 39 // 受信を続ける 40 } while (stream.DataAvailable || resBytes[resSize - 1] != '\n'); 41 //受信したデータを文字列に変換 42 var resMsg = Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length); 43 ms.Close(); 44 //末尾の\nを削除 45 resMsg = resMsg.TrimEnd('\n'); 46 Console.WriteLine(resMsg); 47 48 Console.Read(); 49 } 50 } 51}
最後のコードのみ、送信文字列が異なる(+'\n')ので、送信文字列を同一にしてお試しください。
それでもだめなら、flushを行ってみてください。
最後のコードの+'\n'を消した場合でもうまくいきました.
一つ目のコードに+'\n'を付けたりWriteのあとにFlushしてもうまくいきませんでした.
二つ目のコードは+'\n'を付けてもうまくいきませんがFlushしたときはうまくいきました.
なぜ一つ目のコードではうまくいかないのでしょうか.
「ReadToEnd は、ストリームが最後に到達したことを認識していることを前提としています。 サーバーが要求したときにのみデータを送信し、接続を閉じることができない対話型プロトコルの場合、は終了しないために無期限にブロックすることがあり ReadToEnd ます。これを避ける必要があります。」とのこと
https://docs.microsoft.com/ja-jp/dotnet/api/system.io.streamreader.readtoend?view=net-5.0
ヘッダーにConnection:Closeを追加したところうまく行きました。
ありがとうございます。
回答1件
あなたの回答
tips
プレビュー