質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

3753閲覧

C#のTcpClientをStreamReader/Writerで扱いたいがフリーズしてしまう

abroad128

総合スコア60

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2021/09/15 17:03

編集2021/09/15 17:40

下記コードで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}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YT0014

2021/09/16 00:16

最後のコードのみ、送信文字列が異なる(+'\n')ので、送信文字列を同一にしてお試しください。 それでもだめなら、flushを行ってみてください。
abroad128

2021/09/16 00:24

最後のコードの+'\n'を消した場合でもうまくいきました. 一つ目のコードに+'\n'を付けたりWriteのあとにFlushしてもうまくいきませんでした. 二つ目のコードは+'\n'を付けてもうまくいきませんがFlushしたときはうまくいきました. なぜ一つ目のコードではうまくいかないのでしょうか.
YT0014

2021/09/16 00:31

「ReadToEnd は、ストリームが最後に到達したことを認識していることを前提としています。 サーバーが要求したときにのみデータを送信し、接続を閉じることができない対話型プロトコルの場合、は終了しないために無期限にブロックすることがあり ReadToEnd ます。これを避ける必要があります。」とのこと https://docs.microsoft.com/ja-jp/dotnet/api/system.io.streamreader.readtoend?view=net-5.0
abroad128

2021/09/16 00:38

ヘッダーにConnection:Closeを追加したところうまく行きました。 ありがとうございます。
guest

回答1

0

自己解決

2番目はWriteのあとにFlushしていないため。
1番目はFlushしていないことに加えて接続がキープされていることが原因でした。
ためしにリクエストヘッダー「Connection:Closeを追加したところ、うまくいました。

投稿2021/09/16 00:41

abroad128

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問