我在C#中开发需要网络访问的虚拟化应用程序。我使用ndisprot示例驱动程序读取和写入以太网第2层数据包。除了WriteFile操作需要花费大量时间外,我的一切工作正常。通常在3到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以太网适配器而不是内置适配器,性能更差!它需要15-30秒才能完成写作。这是最离奇的,因为阅读接近瞬间。
Edit2:我的驱动程序有两个线程 - 一个读线程和一个写线程。似乎如果我禁用我的读者线程,写入立即完成。为什么从文件中读取会影响写入?
答案 0 :(得分:1)
您的用户模式代码可能在同步模式下打开句柄。在同步模式下,即使两个不同的线程在同一个句柄上工作,每个句柄一次只能有1个服务。 More here
修复是:
OVERLAPPED
模式打开句柄。如果您可以使用C#进行编码,则可以使用FileOptions.Asynchronous
。NDISPROT样本设计超级简单。它已写入块,直到NIC 完成数据包。这就是写入数百毫秒的原因。此外,由于句柄以同步模式打开,这意味着在第一个数据包完成之前,您无法发送第二个数据包。
对于任何严重的吞吐量来说,方式太慢了;你需要在某处介绍异步。在此处查看更多讨论:Raw ethernet broadcasting