0

ネットワーク アクセスが必要な仮想化アプリケーションを C# で開発しています。ndisprot サンプル ドライバーを使用して、イーサネット レイヤー 2 パケットの読み取りと書き込みを行っています。WriteFile 操作に膨大な時間がかかることを除いて、すべて正常に動作しています。通常は 300 ~ 800 ミリ秒ですが、書き込みが完了するまでに数秒かかる場合があります。

これは、イーサネット パケットをドライバーに書き込む C# 関数です。ストップウォッチを使用して、所要時間を測定しています。

private Stopwatch sw = new Stopwatch();

/// <summary>
/// Writes a layer-2 Ethernet packet to the adapter
/// </summary>
/// <param name="packet">The packet data</param>
/// <returns>true if the write was successful</returns>
public bool WriteEnetPacket(byte[] packet)
{
   int bytesSent = 0;
   bool packetSent = false;

   // Copy the packet data to raw buffer
   IntPtr packetPtr = Marshal.AllocHGlobal(packet.Length);
   Marshal.Copy(packet, 0, packetPtr, packet.Length);

   sw.Restart();
   packetSent = WriteFile(this.handle, 
      packetPtr, 
      packet.Length,
      out bytesSent, 
      0);

   sw.Stop();
   Console.WriteLine("WriteFile completed in {0}ms", sw.Elapsed.Milliseconds);

   // Free the memory
   Marshal.FreeHGlobal(packetPtr);

   // check to see if packet was sent
   if (!packetSent)
   {
      var err = UnsafeMethods.GetLastError();
      var errStr = UnsafeMethods.GetLastErrorString();

      Console.WriteLine("ERROR: Packet not sent: 0 bytes written.");
      Console.WriteLine("Reason: " + errStr);
      return false;
   }

   // otherwise the packet was sent
   Console.WriteLine("Packet sent: " + bytesSent.ToString() + "bytes written");
   return true;
}

アプリケーションを実行すると、出力は次のようになります。有線接続しています。

Packet sent: 42bytes written
WriteFile completed in 160ms
Packet sent: 42bytes written
WriteFile completed in 458ms
Packet sent: 74bytes written
WriteFile completed in 364ms
Packet sent: 74bytes written
WriteFile completed in 51ms
Packet sent: 86bytes written
WriteFile completed in 221ms
Packet sent: 74bytes written
WriteFile completed in 271ms
Packet sent: 74bytes written
WriteFile completed in 1ms
Packet sent: 74bytes written
WriteFile completed in 292ms

アプリケーションに ping を実行すると、応答時間は WriteFile の完了にかかる時間とほぼ一致するため、ハングアップがドライバーのどこかにあることがわかります。これを高速化するためにサンプル ドライバーでできることはありますか? 私は何を間違っていますか?

編集: 今日、内蔵アダプターの代わりに USB-Ethernet アダプターを使用してみましたが、パフォーマンスがさらに低下しました! 書き込みが完了するまでに 15 ~ 30 秒かかります。読み取りはほぼ瞬時に行われるため、これは非常に奇妙です。

Edit2: 私のドライバーには、読み取りスレッドと書き込みスレッドの 2 つのスレッドがあります。リーダースレッドを無効にすると、書き込みが即座に完了するようです。ファイルからの読み取りがファイルへの書き込みに影響するのはなぜですか?

4

1 に答える 1

1

読み取りが書き込みを遅くしているのはなぜですか?

ユーザーモード コードは、おそらく同期モードでハンドルを開きました。同期モードでは、2 つの異なるスレッドが同じハンドルで動作している場合でも、ハンドルごとに一度に 1 つの呼び出ししか処理できません。 詳細はこちら

修正は次のいずれかです。

  • N 個のハンドルを開いてNの同時操作を取得します。また
  • モードでハンドルを開きOVERLAPPEDます。C# でコーディングする余裕がある場合は、FileOptions.Asynchronous.

1 つのパケットを送信するのに 200 ミリ秒かかるのはなぜですか?

NDISPROT サンプルは、非常に単純になるように設計されています。NIC がパケットを完了するまで書き込みブロックがあります。そのため、書き込みは数百ミリ秒です。さらに、ハンドルは同期モードで開かれるため、最初のパケットが完了するまで 2 番目のパケットを送信できません。

これは、深刻スループットには遅すぎます。どこかに非同期性を導入する必要があります。ここで詳細な議論を参照してください: raw イーサネット ブロードキャスト

于 2014-10-03T21:06:46.250 に答える