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

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

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

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

Q&A

1回答

1627閲覧

C#のServicePointManagerの動作について理由がわからない動作があります

abroad128

総合スコア60

C#

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

0グッド

0クリップ

投稿2022/05/10 11:22

編集2022/05/10 11:51

メインのインターフェースは固定回線で、サブのインターフェースにモバイル回線をつなげており、同時に別々のインターフェースでアクセスしたいので以下のコードを試しました。
Windowsでデフォルトのルーティングがメイン回線のほうに設定してあるのでインターフェースを指定しない場合はメイン回線での通信となります。
ここでServicePointManager.MaxServicePointIdleTime = 0;の行を入れない場合は同じServicePointオブジェクトが使いまわされてしまいどちらも最初に作られるモバイル回線を設定したServicePointが使われてしまうのですが、その行を入れるときちんと別々のServicePointオブジェクトが作られてServicePointのハッシュコードも別々となり別々のインターフェースでアクセスとなります。
なぜアイドル時間を0にするとServicePointが新たに作られるような動作になるのでしょうか。

C#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Net; 5using System.Text; 6using System.Text.RegularExpressions; 7using System.Threading.Tasks; 8 9namespace ConsoleApp9 10{ 11 internal class Program 12 { 13 static void Main(string[] args) 14 { 15 while (true) 16 { 17 Console.WriteLine("Start"); 18 ServicePointManager.MaxServicePointIdleTime = 0; 19 Test().Wait(); 20 Console.WriteLine("Done"); 21 Console.ReadLine(); 22 } 23 } 24 25 static async Task Test() 26 { 27 Task task = null; 28 29 // 1回目のリクエスト(インターフェース指定あり) 30 { 31 HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://www.cman.jp/network/support/go_access.cgi"); 32 req.Proxy = null; 33 34 // インターフェースを指定 35 req.ServicePoint.BindIPEndPointDelegate = delegate ( 36 ServicePoint servicePoint, 37 IPEndPoint remoteEndPoint, 38 int retryCount) 39 { 40 return new IPEndPoint(new IPAddress("192.168.42.252".Split('.').Select(s => byte.Parse(s)).ToArray()), 0); 41 }; 42 43 task = new Task(new Action(() => 44 { 45 Console.WriteLine("[1]Start"); 46 Console.WriteLine("[1]Hash=" + req.ServicePoint.GetHashCode()); 47 48 string htmlSource; 49 using (var webres = (HttpWebResponse)req.GetResponse()) 50 using (var st = webres.GetResponseStream()) 51 using (var sr = new System.IO.StreamReader(st, Encoding.UTF8)) 52 { 53 htmlSource = sr.ReadToEnd(); 54 } 55 56 Console.WriteLine("[1]" + Regex.Match(htmlSource, @"\d+.\d+.\d+.\d+").Value); 57 })); 58 59 task.Start(); 60 } 61 62 // 1回目が通信中に2回目が接続するように少し待つ 63 await Task.Delay(50); 64 65 // 2回目のリクエスト(インターフェース指定なし) 66 { 67 HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://www.cman.jp/network/support/go_access.cgi"); 68 req.Proxy = null; 69 70 Console.WriteLine("[2]Start"); 71 Console.WriteLine("[2]Hash=" + req.ServicePoint.GetHashCode()); 72 73 string htmlSource; 74 using (var webres = (HttpWebResponse)req.GetResponse()) 75 using (var st = webres.GetResponseStream()) 76 using (var sr = new System.IO.StreamReader(st, Encoding.UTF8)) 77 { 78 htmlSource = sr.ReadToEnd(); 79 } 80 81 Console.WriteLine("[2]" + Regex.Match(htmlSource, @"\d+.\d+.\d+.\d+").Value); 82 } 83 84 // 非同期の1回目リクエストが終わるのを待つ 85 await task; 86 } 87 } 88}

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

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

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

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

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

guest

回答1

0

ご提示いただいている情報から推測される、MaxServicePointIdleTime未設定時の動作は、以下のようになるかと。

1)1回目のリクエスト処理中に、ServicePointを新規に作成し、その処理に使用。
2)処理終了し、ServicePointはアイドル状態となる。
3)2回目のリクエスト処理中に、ServicePointが必要となり、アイドル状態のServicePointを再利用。

MaxServicePointIdleTime=0にすると、2の時点で、アイドル状態にならず、終了処理が行われるようになります。
その為、3の処理も変わり、新しいServicePointが作成されていると思われます。

なお、MaxServicePointIdleTimeの初期値は100,000 ミリ秒になっているようです。
ServicePointManager.MaxServicePointIdleTime プロパティ

コード内のコメントを読む限り、質問者の想定としては、2回目のリクエスト時には最初のリクエストが終了していないのでしょう。
ですが、動作を見る限り、実際には終了しているようです。
想定通りかどうか、2回目のリクエスト時に、task.Statusなどをチェックされてみることをお勧めします。

投稿2022/05/11 03:12

YT0014

総合スコア1708

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

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

abroad128

2022/05/11 03:24

回答ありがとうございます…! 実際にこのコードを高速なメイン回線と超低速なモバイル回線で試したところ、先に2回目リクエスによるメイン回線のIPアドレスが出てきてその後にしばらくすると1回目リクエストのモバイル回線のIPアドレスが出てきました。(アクセスしてるURLはIPアドレス表示サイトでレスポンスからIPアドレスを抽出して表示するようになっています)
abroad128

2022/05/11 03:35

出力イメージはこのような感じです。 Start [1]Start [1]Hash=111111 [2]Start [2]Hash=222222 [2]メイン回線のアドレス [1]モバイル回線のアドレス Done
YT0014

2022/05/11 13:37

申し訳ございませんが、abroad128さんの主張が把握できていません。 当方の推測した「1回目のリクエストが2回目のリクエスト以前の終了」は、出力結果から誤りと思われるということでしょうか? それとも、モバイル回線をより低速にしてみたら、期待通りの結果になったということでしょうか?
abroad128

2022/05/11 15:09

そうですね。 最初の質問文で書いておくべきでしたが1回目の通信中、終了前までの間に2回目が通信を開始しているように思います。
abroad128

2022/05/11 15:10

モバイル回線をより低速にしてみたら期待通りの結果になったわけではなく、質問時点で最初の返信の動作をすることを確認していました。
YT0014

2022/05/11 23:56

ご返信ありがとうございます。 この場合、問題になるのが、ServicePointがアイドルになるタイミングがいつなのか?ということです。 abroad128さんは、レスポンスの完了後だと判断されているようですが、マニュアルなどを読んだ限りでは、リクエストの到達確認後、アイドルになる可能性があります。(残念ながら、どちらの可能性も、情報がありませんでしたが) 方法が思いつけず、申し訳ないのですが、確認が必要な点かと考えます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問