カーネル モードで送信完了パスを削除することはできません。その理由は、最終的に送信完了を発行するまで、ネットワーク カードがメモリからバイトを読み取るのにビジーであるためです。パケットを再利用する前に送信完了を待たなかった場合、ネットワーク カードは完全なパケットを読み取る機会がありませんでした。破損したデータを送信することになります。
しかし、在庫の NDISPROT サンプルを使用して大量のデータを送信すると、効率が大幅に低下することは間違いありません。問題は、NDISPROT のユーザーモード サンプル アプリケーションがデータをカーネルモードに同期的に書き込むことです。つまり、スレッドは書き込み (パケットの送信) を開始し、書き込み (パケットの送信) が完了するまでブロックします。(NDISPROT サンプルの目的は、カーネル モードで NDIS と相互運用する方法を説明することであり、ユーザーとカーネルの通信に関する複雑な手法を説明することではないため、このサンプルは非効率的です)。
複数のデータを同時に発行するいくつかの手法のいずれかを使用すると、これを大幅に高速化できます。
マルチスレッドを使用します。複数のスレッドで並行して行うことを除いて、今行っているのと同じことを行います。これは非常に簡単に設定できますが、スケーリングがうまくいきません (トラフィックを 10 倍にスケーリングするには、10 倍のスレッドが必要であり、キャッシュの問題が発生し始めます)。さらに、データセットを順番に送信する必要がある場合は、スレッドがリクエストを順番に発行できるようにするために、一連の複雑な同期が必要になります。
WriteFile および OVERLAPPED データ構造で非同期呼び出しを使用します。これには、ユーザーモード アプリでいくつかのツールを変更する必要があります。(幸い、カーネル ドライバーは既にサポートされているため、カーネル ドライバーに触れる必要はありません)。OVERLAPPED 書き込みを使用すると、1 つのスレッドから複数の同時書き込みを発行し、それらのいずれか (またはすべて) が完了したときに通知を受け取ることができます。重複する設計に十分注意すれば、100Mbps のネットワーク リンクを簡単に埋めることができるはずです。
より明確にするために、これはあなたが現在持っているものです:
Your app NDISPROT driver Network card The network
---------------------------------------------------------------------------------
WriteFile
. \-------> NdisProtWrite
. \-------> NdisSendPackets
. |
. (copy packet payload
. from system RAM to
. network card's buffer)
. |
. |---------------> Start sending
. NdisProtSendComplete <---------| .
WriteFile <----/ | .
returns |<--------------- Finish sending
ご覧のとおり、ユーザー モード アプリは、ネットワーク カードが RAM から NIC ハードウェアにパケット ペイロードをコピーしている間ずっと、WriteFile でスタックしています。代わりに、kernelmode への非同期書き込みを使用すると、次のようになります。
Your app NDISPROT driver Network card The network
---------------------------------------------------------------------------------
WriteFile
. \-------> NdisProtWrite
. | \-------> NdisSendPackets
WriteFile <------/ |
returns (copy packet payload
from system RAM to
network card's buffer)
|
|---------------> Start sending
NdisProtSendComplete <---------| .
Async write <--/ | .
completes |<--------------- Finish sending
このセットアップでは、WriteFile がより迅速に返されるため、NIC がまだ最初のパケットを読み取っている間に、別のパケット (または 10) をキューに入れる機会があります。通常の OVERLAPPED 手法のいずれかを使用して、書き込み (パケットの送信) がいつ完了したかを判断し、データ バッファーを再利用できます。
非同期 I/O の使用を開始するには、このドキュメントから始めてください。(おっと、彼らの図は私の素晴らしい ASCII アートから 90° 回転しているように見えます...)。