質問

Delphi でネットワーク コードを作成する人々が Windows スタイルのオーバーラップ非同期ソケット I/O を使用する通常の方法は何ですか?

この質問に対する私の以前の調査は次のとおりです。

インディ コンポーネントは完全に同期しているように見えます。一方、ScktComp ユニットは WSAAsyncSelect を使用しますが、基本的には BSD スタイルの多重化ソケット アプリを非同期化するだけです。ループ内の select() から戻ったかのように、単一のイベント コールバックでダンプされ、ステート マシンのナビゲーションをすべて自分で行う必要があります。

.NET の状況は、Socket.BeginRead / Socket.EndRead を使用するとかなり良くなり、継続が Socket.BeginRead に直接渡され、そこから再開されます。クロージャとしてコード化された継続には、明らかに、必要なすべてのコンテキストなどが含まれています。

役に立ちましたか?

解決

非同期のものについては、ICS を試してください

http://www.overbyte.be/frame_index.html?redirTo=/products/ics.html

他のヒント

Indy は当初はより単純なコンセプトでしたが、アプリケーションの終了時にスレッドを解放するためにソケットを強制終了する必要があるため、管理が面倒であることがわかりました。さらに、OS パッチのアップグレード後に Indy ライブラリが動作しなくなってしまいました。ScktComp は私のアプリケーションではうまく機能します。

@Roddy - 同期ソケットは私が求めているものではありません。接続の存続期間が長くなる可能性があるためにスレッド全体を燃やすということは、同時接続の量をプロセスに含めることができるスレッドの数に制限することを意味します。スレッドは、予約されたスタック アドレス空間、コミットされたスタック メモリ、コンテキスト スイッチのためのカーネル遷移など、多くのリソースを使用するため、数百の接続、ましてや数千以上の接続をサポートする必要がある場合には拡張できません。

Delphiでネットワークコードを書く人々がWindowsスタイルの非同期ソケットI/Oを使用する通常の方法は何ですか?

さて、Indy は長い間ソケット I/O の「標準」ライブラリであり、ソケットのブロックに基づいています。これは、非同期動作が必要な場合は、追加のスレッドを使用してデータの接続/読み取り/書き込みを行うことを意味します。私の考えでは、これは実際に大きな利点です。ステート マシン ナビゲーションを管理したり、コールバック プロシージャや類似のものについて心配したりする必要がないからです。私の「読み取り」スレッドのロジックは、ノンブロッキングソケットよりも乱雑ではなく、はるかに移植性が高いことがわかりました。

インディ 9 ほとんど耐爆性があり、高速で信頼性が高くなります。しかし、ティブロンのインディ10への移籍は私に少し心配を引き起こしています。

@マイク:「...スレッドを解放するにはソケットを強制終了する必要がある...」。

これにより「ええ?」私たちのスレッドライブラリは、例外ベースの手法を使用して「待機」スレッドを安全に殺すために覚えています。私たちは電話します キューユーザーAPC スレッド ラッパー プロシージャによってのみキャッチされる C++ 例外 (クラス Exception から派生したものではありません) を発生させる関数をキューに入れます。すべてのデストラクターが呼び出されるため、スレッドはすべてき​​れいに終了し、途中で整理されます。

「同期ソケットは私が求めているものではありません。」

わかりました - しかし、その場合、最初の質問に対する答えは、Delphi が存在しないということだと思います 熟語 非同期ソケット IO は、実際には高度に専門化された一般的ではない要件であるためです。

副次的な問題として、これらのリンクが興味深いと思われるかもしれません。どちらも少し古くて、Windows よりも「nxy」です。2 番目の条件は、適切な環境では、スレッドが思ったほど悪くない可能性があることを意味します。

C10K問題

イベントがなぜ悪い考えなのか (同時実行性の高いサーバーの場合)

@Chris Miller - 回答で述べたことは事実上不正確です。

WSAAsyncSelect を通じて利用できる Windows メッセージ スタイルの非同期は、確かに、Win 3.x 時代に適切なスレッド モデルが欠如していたことに対する主な回避策です。

ただし、.NET Begin/End は ない 余分なスレッドを使用します。代わりに、WSASend / WSARecv の追加の引数、特にオーバーラップ完了ルーチンを使用してオーバーラップ I/O を使用し、継続を指定します。

これは、.NET スタイルが Windows OS の非同期 I/O サポートを利用して、 避ける ソケットをブロックしてスレッドを書き込みます。

一般にスレッドは高価であるため (CreateThread に非常に小さいスタック サイズを指定しない限り)、ソケット上でスレッドがブロックされると、10,000 の同時接続に拡張できなくなります。

これが、拡張したい場合に非同期 I/O を使用することが重要である理由であり、.NET が重要である理由でもあります。 ない, 繰り返しますが、 ない, 、単に「スレッドを使用し、[...] フレームワークによって管理されているだけです」。

@Roddy - あなたが指しているリンクをすでに読みました。どちらも Paul Tyma のプレゼンテーション「Thousands of Threads and Blocking I/O - The old way to write Java Servers is again」から参照されています。

ただし、Paul のプレゼンテーションから必ずしも浮き彫りになるわけではない点は、彼が起動時に JVM に -Xss:48k を指定したこと、および JVM の NIO 実装が有効であるために効率的であると想定していることです。比較。

インディはそうします ない 同様に縮小され、厳しく制限されたスタック サイズを指定します。Indy コードベースには、BeginThread (Delphi RTL スレッド作成ルーチン。このような状況で使用する必要があります) や CreateThread (生の WinAPI 呼び出し) への呼び出しはありません。

デフォルトのスタック サイズは PE に保存され、Delphi コンパイラの場合、デフォルトで 1MB の予約されたアドレス スペースになります(スペースは OS によって 4K チャンクでページごとにコミットされます)。実際、関数内に 4K を超えるローカルがある場合、コンパイラはページにアクセスするコードを生成する必要があります。これは、拡張機能がページ フォールトによって制御されるためですが、スタック内の最下位 (ガード) ページのみが対象です。つまり、最大 2,000 の同時スレッドが接続を処理すると、アドレス空間が不足してしまいます。

現在、{$M minStackSize [,maxStackSize]} ディレクティブを使用して PE のデフォルトのスタック サイズを変更できますが、これは影響を及ぼします。 全て メインスレッドを含むスレッド。48K または (同様の) スペースはそれほど多くないので、再帰はあまり行わないことを望みます。

さて、特に Windows の非同期 I/O の非パフォーマンスについて Paul が正しいかどうかは、私にも 100% 確信はありません。確実にするには測定する必要があります。ただし、私が知っているのは、スレッド化プログラミングの方が非同期イベントベースのプログラミングよりも簡単であるという議論が、 誤った二分法.

非同期コードはそうではありません 必要 イベントベースであること。.NET と同様に継続ベースにすることができ、継続としてクロージャを指定すると、状態が無料で維持されます。さらに、線形スレッド スタイルのコードから継続渡しスタイルの非同期コードへの変換は、コンパイラーによって機械的に行うことができるため (CPS 変換は機械的です)、コードの明瞭性を犠牲にする必要もありません。

無料の IOCP (完了ポート) ソケット コンポーネントがあります。 http://www.torry.net/authorsmore.php?id=7131 (ソースコードが含まれています)

「ナベレグヌ・セルゲイ・N..Windows完成ポートに基づいて、Windowsソケット拡張機能を使用した高性能ソケットサーバー。IPv6がサポートされています。」

私の小さなインスタントメッセージングサーバーを再構築するために、より良いコンポーネント/ライブラリを探していたときに見つけました。まだ試していませんが、第一印象としてはコーディングが良さそうです。

Indy は、より簡単なプログラミング方法であるため、同期ソケットを使用します。非同期ソケットのブロックは、Windows 3.x の時代に winsock スタックに追加されたものです。Windows 3.x はスレッドをサポートしておらず、スレッドなしではソケット I/O を実行できませんでした。Indy がブロッキング モデルを使用する理由についての追加情報については、以下を参照してください。 この記事.

.NET Socket.BeginRead/EndRead 呼び出しはスレッドを使用しており、ユーザーではなくフレームワークによって管理されているだけです。

@Roddy、Indy 10 は Delphi 2006 以降、Delphi にバンドルされています。インディ 9 からインディ 10 への移行は簡単な作業であることがわかりました。

ScktComp クラスでは、NonBlocking サーバー タイプではなく ThreadBlocking サーバーを使用する必要があります。OnGetThread イベントを使用して、ClientSocket パラメータを設計の新しいスレッドに渡します。TServerClientThread の継承インスタンスをインスタンス化したら、ソケットの読み書きに使用できる TWinSocketStream のインスタンス (スレッド内) を作成します。このメソッドを使用すると、イベント ハンドラーでデータを処理する必要がなくなります。これらのスレッドは、読み取りまたは書き込みが必要な短期間だけ存在することも、再利用する目的で一定期間ハングアップすることもできます。

ソケットサーバーの作成の主題はかなり広範囲に及びます。実装を選択できるテクニックや実践方法は数多くあります。TServerClientThread で同じソケットに読み書きする方法は簡単で、単純なアプリケーションには問題ありません。高可用性と高同時実行性のモデルが必要な場合は、Proactor パターンのようなパターンを検討する必要があります。

幸運を!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top