Невозможно исключить путь отправки-завершения в режиме ядра.Причина состоит в том, что сетевая карта занята чтением байтов из памяти, пока она наконец не выдаст завершение отправки.Если вы не дожидаетесь завершения отправки перед повторным использованием пакета, то у сетевой карты не было бы возможности прочитать полный пакет.В конечном итоге вы отправите поврежденные данные.
Но вы правы, что при использовании стандартного образца NDISPROT для отправки огромных объемов данных возникает большая неэффективность.Проблема в том, что пример приложения пользовательского режима NDISPROT записывает данные в режим ядра синхронно .Это означает, что ваш поток начинает запись (отправка пакета), а затем блокируется до завершения записи (отправка пакета).(Этот пример неэффективен, потому что цель примера NDISPROT состоит в том, чтобы проиллюстрировать, как взаимодействовать с NDIS в режиме ядра, а не иллюстрировать сложные методы взаимодействия с ядром пользователя.)
Вы можете значительно ускорить это, используяодин из нескольких способов одновременной выдачи нескольких фрагментов данных:
Использовать многопоточность.Сделайте то же самое, что вы делаете сейчас, за исключением того, что вы делаете это одновременно на нескольких потоках.Это довольно просто настроить, но он не очень хорошо масштабируется (для масштабирования до 10-кратного трафика вам понадобится 10-кратные потоки, и вы начинаете страдать от проблем с кэшированием).Кроме того, если ваш набор данных должен быть отправлен по порядку, вам нужна куча сложной синхронизации, чтобы убедиться, что потоки выдают запросы по порядку.
Используйте асинхронные вызовы с структурами данных WriteFile и OVERLAPPED.Это требует от вас переоборудования в приложении usermode.(К счастью, вам не нужно прикасаться к драйверу ядра, поскольку это уже поддерживает это).При записи OVERLAPPED вы можете выполнить несколько одновременных записей из одного потока, а затем получать уведомление, когда какая-либо (или все) из них завершается.Если вы достаточно осторожны с перекрывающимся дизайном, вы сможете легко заполнить сетевой канал со скоростью 100 Мбит / с.
Чтобы быть более точным, это то, что у вас сейчас есть:
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
Как видите, ваше приложение пользовательского режима застревает в WriteFile все время, пока сетевая карта копирует полезную нагрузку пакета из ОЗУ на оборудование NIC.Вместо этого, если вы используете асинхронную запись в режим ядра, вы получите следующее:
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 возвращается быстрее, и у вас есть шанс поставить в очередьдо другого пакета (или 10), пока NIC все еще читает первый пакет.Вы можете использовать любой из обычных методов OVERLAPPED, чтобы определить, когда запись (отправка пакета) завершена, и вы можете повторно использовать буфер данных.
Чтобы начать работу с асинхронным вводом / выводом, начните с thisдокументация .(Упс, похоже, что их диаграммы повернуты на 90 ° от моего удивительного ASCII-арта ...).