2009-07-24 5 views
6

私は、ctypesモジュールを使用してPythonでWindows DLL APIを使用してIO完了ポートベースのサーバー(source code here)を作成しています。しかしこれはAPIのかなり直接的な使い方であり、この質問はPythonではなくIOCPの知識を持っている人を対象としています。IO完了ポートキーの混乱

私はCreateIoCompletionPortのドキュメントを理解しているので、作成したIOCPに関連付けるファイルハンドル(私の場合はソケット)を使ってこの関数を呼び出すと、 "ユーザー定義の"完了キーを指定します。 GetQueuedCompletionStatusを呼び出すときには、オーバーラップしたオブジェクトへのポインタとともに完了キー値を取得します。完了キーは、重複したオブジェクトと要求が完了したことを特定する必要があります。

しかし、CreateIoCompletionPort呼び出しで、オーバーラップしたオブジェクトを使用して完了キーとして100を渡したとします。同じオーバーラップしたオブジェクトがIOを完了し、GetQueuedCompletionStatusを介して戻ってくると、それに付随する完了キーは元の値の100にほとんど似ていません。

完了キーの仕組みを誤解していますか。上記のリンク先のソースコードで間違っている必要がありますか?

答えて

1

GetQueuedCompletionStatusは、OVERLAPPED構造体と完了キーの2つを返します。完了キーはデバイスごとの情報を表し、OVERLAPPED構造体は通話情報を表します。完了キーは、CreateIoCompletionPortへの呼び出しで指定されたものと一致する必要があります。通常、接続に関する情報を含む構造体へのポインタを補完キーとして使用します。

completionKeyで何もしていないようですが、返信はGetQueuedCompletionStatusです。

私はあなたが欲しい推測している:

if completionKey != acceptKey: 
    Cleanup() 
    ... 

が編集:

Pythonは何とかCreateAcceptSocketで作成しOVERLAPPED構造は、Win32 APIで非同期的に使用されていることを知っているし、GCであることから、それを防ぐん」 d?

+0

"CreateIoCompletionPort呼び出しで完了キーとして100を渡したとしましょう。同じオーバーラップオブジェクトがIOを完了し、GetQueuedCompletionStatusを通じて戻ってくると、それに伴う完了キーははるかに大きく、 100の元の値には似ていません。私の質問から、なぜ私はソースコードでそれを比較していません。 重複したオブジェクトがガベージコレクションされている可能性はありますが、これは質問とは関係ありません。 –

0

問題は、完了キーをどのように渡しているかにあります。完了キーの引数はポインタですが、指し示された値ではなくポインタを返すので、少なくとも私は少し混乱します。

また、受け入れられた接続オーバーラップパケットに対して渡された完了キーは、受け入れられたソケットのものであり、受け入れられたソケットのものではありません。

4

私が毎日の練習で見つけたのは、変更されていないので、OVERLAPPEDの結果に焦点を当てることが最もよいことです。あなたはそれを効果的に使用することができます1つの方法は、以下のようなものを持っていることです。

struct CompletionHandler 
{ 
    OVERLAPPED dummy_ovl; 
    /* Stuff that actually means something to you here */ 
}; 

あなたがIOCPに何か(I/OコールやWin32 APIを使用してちょうどポストを経由するかどうか)を投稿すると、あなたが最初に作成CompletionHandlerオブジェクトを呼び出し、そのオブジェクトのアドレスをOVERLAPPED*にキャストします。

CompletionHander my_handler; 
// Fill in whatever you need to in my_handler 
// Don't forget to keep the original my_handler! 

// I/O call goes here, and for OVERLAPPED* give: (OVERLAPPED*)&my_handler 

この方法で、あなたはあなたがしなければならないすべてはCompletionHandlerと出来上がりに戻ってそれを投げているOVERLAPPED結果を取得するときに!あなたはあなたの呼び出しの元のコンテキストを持っています。現実世界の設定で詳細について

OVERLAPPED* from_queued_completion_status; 
// Actually get a value into from_queued_completion_status 

CompletionHandler* handler_for_this_completion = (CompletionHandler*)from_queued_completion_status; 
// Have fun! 

、Windows用ASIO(ver 1.42 header here)のブーストの実装をチェックしてください。あなたがGetQueuedCompletionStatusから得るOVERLAPPEDポインタの検証のようないくつかの詳細がありますが、実装する良い方法についてはリンクを再度ご覧ください。

0

補完キーはポインタではなく、ULONG_PTR型の番号で、「ポインタの大きさの整数」という意味で、x64では32ビット、x64では64ビットです。 typenameは混乱しますが、win32のtypemamesがポインタを参照するとき、終わりではなく名前の前にPを付けることでポインタを参照します。

0

アプリケーションがマルチスレッドの場合は、渡すCompletionKeyが定数であるか、スタック上ではなくヒープ上にオブジェクトを指すポインタ値であることを確認してください。 100が定数として渡されたあなたの例では、何らかの変更を言うのは間違っていなければなりません。しかし、この問題に関しては、CreateIoCompletionPortでソケットハンドルを渡しても、GetQueuedCompletionStatusでハンドルを取得して参照することはできません。あなたは

HANDLE socket; 
CreateIoCompletionPort((HANDLE)socket, existed_io_completion_port, (ULONG_PTR)socket, 0); 
/*some I/Os*/ 
... 

HANDLE socket; 
GetQueuedCompletionStatus(existed_io_completion_port, &io_bytes_done, (PULONG_PTR)&socket, &overlapped); 

とブラケットの種類に注意を払うを行うことができます。

1

完了キーは「接続ごとの」データと(拡張された)オーバーラップ構造を 'per i/o'操作として考える必要があります。

BOTHに拡張オーバーラップ構造を使用し、必要なすべての情報を拡張オーバーラップ構造に格納する人がいます。私はいつも私のソケットを完了キーにラップする参照カウントオブジェクトと、参照カウントデータバッファを拡張オーバーラップ構造として保存してきました。興味があればsome example IOCP code in C++ hereをご覧ください。

完了キーは、事実上、ソケットの補完が完了したときにI/O補完システムが返すデータに対する不透明なハンドルです。