DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Tipsの評価に対するコメントへのレスです

分類:[.NET]

文章が長くなってしまいましたので、こちらに投稿させていただきます。
この記事に対するレスの前にご自分で一度動作検証を行ってください。
MSDNの記事はあくまでリファレンスです。

>ちなみに、Stream.Closeは接続を解放するとMSDNにあります。

確かにMSDNにそう記述がありますが。。
もちろんストリームはClose()されるべきです。
しかし、ストリームを閉じても通信(ソケット)を閉じたとは正確には"判断されない"ということに注意してください。
ストリームはあくまで接続(RequestやResponse等のネットワーク通信に関するオブジェクト)からデータを読み出すものであって接続そのものではありません。

.NETで作成した接続オブジェクト(抽象的な言い方ですが一概にソケットとは言えないので)はアプリケーション終了時に自動的に破棄されるので同じサーバーに複数回接続する予定がない場合はまぁ、問題はないかも知れません。

しかし、同一アプリケーションが複数回同じサーバーに接続する場合、特に相手との信頼関係を重視するSSL通信においては一度開いたRequestを破棄してからでないと内部的には「すでに接続済みの相手のはずなのにまた接続しようとしている 偽者の可能性がある」と判断されると思われます(未検証)。https通信の有効性のチェック(メソッド)をオーバーライドしてエラーにならないようにしてしまえば問題はないですが、それを行わない場合は

System::Net::WebRequest* req;
req->Abort();

Abort()メソッドを呼び出して破棄、接続の終了を明確にしなくてはいけません。
そうしないとサーバーとの信頼関係を確立できず、エラーが返ってきます。
http通信では必ずしもこの限りではありませんが、それでもきちんとAbort()するのが正しい手順だと思います。
少なくとも私が開発を行う限り、このメソッドを呼び出さなければ期待通り動作致しません(検証済み)

しかし私の開発はManaged C++開発なのでC#と動作が異なる場合があるかもしれません。C#はあまり慣れませんができる限りの検証は致しました。それでももしそうでしたら板汚しをおゆるしください。
2005/03/30(Wed) 04:54:35 編集(管理者)
2005/03/30(Wed) 04:39:19 編集(管理者)

わざわざ詳しくありがとうございました。

私の理解では、Abortメソッドは通常非同期メソッドを使って通信している最中に中断するために使用します。

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemnethttpwebrequestclassaborttopic.asp

逆アセンブラで調べてみましたが、Stream(ConnectStream)のCloseメソッドで状況によりAbortが呼び出されるようです。(HttpWebRequestのAbortでもStreamのCloseが間接的に呼び出されているようです。)MSDNにあるように、やはりStreamのCloseだけで十分だと思うのですが。

#はじめて読む方には問題の記事がどこか分からないと思いますので、リンク先を記します。

http://dobon.net/vb/dotnet/internet/webrequestpost.html
丁寧な返答ありがとうございます。
StreamのClose()メソッドでAbort()が呼び出されるというのは初耳です。
なるほど、確かに理論上はClose()だけで十分なようですね。

しかし会社のものなのでここにコードを貼り付けるわけにいきませんが、
必ず最後にAbort()しないと次回接続の際にプログラムがエラー終了してしまう
という現象が起こっているのは事実です。
しかも今のところ非同期処理は使用していません。

ここで確認の必要がありそうな事項は以下だと思います。

*Streamが呼び出すAbortはWebRequestのAbortなのか。StreamのAbortなのではないのか?

*WebRequest.Abort()は非同期処理中の破棄のためのみに呼び出されるべきものなのか?

*そうだとしたら私の側で開発中のシステムで予期せぬ非同期処理(何らかの人為的ミスか不具合)が発生しているのか?

ちょっと再度確認してみましょう
WebRequestのAbortは、どぼんさんの書いてる通り、というか、MSDNにも載ってるとおり、
要求のキャンセルで、リソース解放が目的のメソッドではないと思います。
(もちろん、その際には、必然的に、リソース解放も行われるでしょうが。)
実際に必要なのはキャンセルではなく閉じることによる解放であって、
Abortを呼ぶ必要があるわけではないと思います。
(キャンセル目的以外でAbortを明示的に実行するとプログラマが何か混乱しそうです。)

WebRequest側のAbort云々ではなく、WebResponse側のCloseを呼んでいないだけだったりはしませんか?
どぼんさんのサンプルコードにはありませんが、
MSDN中のサンプルでも、StreamのCloseの後でも、レスポンスのCloseを改めて呼んでいるようですし。

応答リソースそのものがWebResponseで、それの読み取り処理をするための手段としてStreamが
提供されている構造・関係上の理屈から言っても、ストリームを閉じてもレスポンス自体は
勝手に閉じられない可能性はあると思います。
WebResponseのCloseの説明を見ると
「Close メソッドは、 WebResponse によって使用されたリソースをクリーンアップし、 
Stream.Close メソッドを呼び出して、元になるストリームを閉じます。」
となっていますから、レスポンスをCloseすると従属しているStreamのCloseは自動的に呼ばれるようです。

ので、
両方閉じる、もしくは、レスポンスのCloseを使用する、のがよいのでは。
(私はMSILレベルで細かく中見たり逆アセンブルとかしたりできませんけど。)
> *Streamが呼び出すAbortはWebRequestのAbortなのか。StreamのAbortなのではないのか?

もちろんWebRequestのつもりで書きました。

> *WebRequest.Abort()は非同期処理中の破棄のためのみに呼び出されるべきものなのか?

WebRequest.AbortでもStreamのCloseが呼び出されているようなので、同期で使用しても問題ないと思いますが、StreamのCloseで閉じられるならば、Abortを呼び出す必要がありませんし、不自然のように思われます。

> *そうだとしたら私の側で開発中のシステムで予期せぬ非同期処理(何らかの人為的ミスか不具合)が発生しているのか?

さらに調べてみたところ、面白いことが分かりました。StreamのCloseでWebRequest.Abortを呼び出しているのは.NET Framework1.1で、1.0ではこの処置が抜けているようなのです。talkingdebugger C++さんは1.0をご使用ではないでしょうか?
> WebRequest側のAbort云々ではなく、WebResponse側のCloseを呼んでいないだけだったりはしませんか?

もちろん、レスポンスのClose()はしてます。



間違わないでいただきたいのはこの板の趣旨は現在、
問題点の探求であって私は管理人さんをどうこう批判しようというつもりは
全くありません。

あくまで今は意見と情報の交換を行っているつもりです。

スレの内容を読んでいただければわかると思いますが、管理人さんからの情報、
再度MSDNの情報と照らし合わせても原因不明の動作が(管理人さんのソースをコピぺしても起こりました。Abortでエラーなく処理できました)起こっていることは確かです。
MSDNの記述からまだ私が読み取れていない動作がある可能性もあります。
もしかしたら組み上げたサーバー側の問題かもしれません。

繰り返しますが管理人さんのコードどおりではなんらかの原因でサーバーとの接続に失敗することがあるということです。
管理人さん、またはMSDNの言うとおりに処理してないのではないか。というのは前提として間違っています。
私は管理人さんやMSDNが間違っているとは全く言っていません。
(この板の前にはそのような言い方をしたかもしれませんが、ここではそうではありません)
どこに問題があるか現段階ではっきりしないからです。
この板はそれについて考えうる可能性と情報を交換しあいたいという目的で進行させようと考えていました。
誤解を招いたかもしれません。すみませんでした。

今後、「管理人さんの味方」という立場のレスがつくことは私の望むことではありません。

詳しい調査が終了、報告できるまで板を閉じさせていただきます。
解決済み!
2005/04/03(Sun) 05:34:39 編集(投稿者)

talkingdebugger C++さんのご心配されている誤解は、こど。さんもその他の閲覧者の方もしていないのではないかと思います。少なくとも私は、Tips記事にコメントを付けられるようにしている目的の一つは情報収集で、talkingdebugger C++さんの投稿はその目的に合致しており、本当に感謝しています。

ただ、talkingdebugger C++さんがなぜ私の投稿( No10227 )を無視されたのかが分かりません(見損ねただけとは思いますが...)。もしこの問題が.NET Framework1.0のバグで、talkingdebugger C++さんが1.0を使っていらっしゃるとすれば、つじつまが合うと思うのですが。

talkingdebugger C++さんが使っていらっしゃったのは、.NET Framework1.0か否かだけ教えていただけませんか?
> ただ、talkingdebugger C++さんがなぜ私の投稿( No10227 )を無視されたのかが分かりません(見損ねただけとは思いますが...)。もしこの問題が.NET Framework1.0のバグで、talkingdebugger C++さんが1.0を使っていらっしゃるとすれば、つじつまが合うと思うのですが。
>
> talkingdebugger C++さんが使っていらっしゃったのは、.NET Framework1.0か否かだけ教えていただけませんか?

すみません。無視したわけではないのですが書き足し忘れていました。
.NET Framework1.1です。
知り合いのMS関係の方(ビル・ゲイツと握手してるような人です(笑))に聞きましたところ、Close内で呼び出されてるとされるAbortはいわゆる「念のため」で非同期してない場合ほぼ影響がないだろうというお話でした。

やはりサーバーの方がどこかで非同期処理を行っているのだろうというのがその方の意見でした。
しかしWebRequest.BeginGetResponseでなくても非同期要求を開始できるのでしょうか?
とりあえずサーバー群を漁ってみますが1.1でClose内でAbortされてるならなぜもう一度呼び出す必要があるのだろう?などしっくりいかない部分が残りますね。
お返事ありがとうございました。

> やはりサーバーの方がどこかで非同期処理を行っているのだろうというのがその方の意見でした。
> しかしWebRequest.BeginGetResponseでなくても非同期要求を開始できるのでしょうか?

GetRequestStreamメソッドもBeginGetResponseを呼び出しているようです。関係あるかは分かりませんが。

> とりあえずサーバー群を漁ってみますが1.1でClose内でAbortされてるならなぜもう一度呼び出す必要があるのだろう?などしっくりいかない部分が残りますね。

私も詳しく調べたわけではありませんが、Closeで必ずAbortが呼び出されるわけではないので、もしかしたら何らかの理由でAbortを呼び出していないということもありえるかもしれません。ともあれ、何とも不可解ですね。

DOBON.NET | プログラミング道 | プログラミング掲示板