10

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

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

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

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

4

10 に答える 10

2

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

于 2008-09-01T00:02:03.263 に答える
2

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

于 2008-09-01T19:51:09.927 に答える
1

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

理解しましたが、その場合、元の質問に対する答えは、非同期ソケットIOのDelphiイディオムは実際には高度に専門化された珍しい要件であるため、存在しないということだと思います。

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

C10K問題

イベントが悪いアイデアである理由(同時実行性の高いサーバーの場合)

于 2008-09-02T09:57:59.407 に答える
1

@ChrisMiller-あなたがあなたの答えで述べたことは事実上不正確です。

WSAAsyncSelectを介して利用できるWindowsメッセージスタイルの非同期は、実際、Win3.x日で適切なスレッドモデルが不足している場合の回避策です。

ただし、.NET Begin / Endは、追加のスレッドを使用していません。代わりに、重複I / Oを使用し、WSASend / WSARecvの追加の引数、具体的には重複完了ルーチンを使用して、継続を指定します。

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

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

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

于 2008-09-04T19:18:27.220 に答える
1

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

「Naberegnyh Sergey N 著..Windows Completion Port に基づき、Windows Socket Extensions を使用した高性能ソケット サーバー。IPv6 をサポート。」

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

于 2009-01-13T00:40:49.473 に答える
1

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

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

Indy 9は、ほとんどの場合防爆性、高速性、信頼性に優れています。しかし、ティブロンのインディ 10 への移行は、私に少し懸念を引き起こしています。

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

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

于 2008-09-01T16:12:18.800 に答える
1

@Roddy - あなたが指し示しているリンクをすでに読みました。どちらも、Paul Tyma のプレゼンテーション「何千ものスレッドとブロッキング I/O - Java サーバーの古い書き方が再び新しくなりました」から参照されています。

ただし、Paul のプレゼンテーションから必ずしも飛び出しているとは限らないことのいくつかは、起動時に -Xss:48k を JVM に指定したことと、JVM の NIO 実装が有効であるためには効率的であると想定していることです。比較。

Indy は、同様に縮小され、厳密に制約されたスタック サイズを指定していません。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 変換は機械的に行われます)、コードの明快さを犠牲にする必要もありません。

于 2008-09-04T19:44:27.030 に答える
0

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

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

@ Roddy、Indy10はDelphi2006からDelphiにバンドルされています。Indy9からIndy10への移行は簡単な作業であることがわかりました。

于 2008-09-03T19:47:17.563 に答える
0

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

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

于 2008-09-10T03:27:22.943 に答える
0

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

ソケット・サーバーを作成する主題はかなり広範囲です。実装するために選択できる多くの手法とプラクティスがあります。TServerClientThread で同じソケットに読み書きする方法は簡単で、単純なアプリケーションには適しています。高可用性と高同時実行性のモデルが必要な場合は、Proactor パターンのようなパターンを検討する必要があります。

幸運を!

于 2008-09-11T20:47:51.670 に答える