Почему мой вызов TransmitFile работает плохо по сравнению с другими методами?
Сначала немного предыстории - я пишу базовый FTP-сервер для личного проекта. В настоящее время я работаю над получением файлов. Моя текущая реализация выглядит так:
HANDLE hFile = CreateFile("file.tar.gz", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
TransmitFile(sd, hFile, fileSize, 65536, NULL, NULL, TF_USE_KERNEL_APC | TF_WRITE_BEHIND);
CloseHandle(hFile);
Это работает, но производительность сомнительна. Сначала передача начинается примерно с 10 МБ / с, но постепенно уменьшается до 3 МБ / с. Используя FileZilla Server и IIS FTP, он поддерживает постоянную скорость передачи>30 МБ / с. Поэтому я знаю, что он не работает на полную мощность. Я пробовал возиться с размером буфера, но это не улучшило производительность. Если у кого-нибудь есть предложения по более эффективному способу передачи файла, пожалуйста, дайте мне знать. Документация по API, кажется, предполагает, что TransmitFile был оптимизирован для моего приложения, поэтому я решил использовать его.
[Прошу прощения за отсутствие знаний о API Windows.]
Также все сокеты открываются на локальном хосте.
3 ответа
Увеличили ли вы размер буфера TCP сокета (и, возможно, размер окна TCP), установив SO_SNDBUF
а также SO_RCVBUF
варианты сокетов, прежде чем начать передачу? (сделать это после привязки и до подключения)?
Судя по звучанию проблемы, более быстрый запуск, который затем замедляется, я думаю, что это проблема управления потоком TCP (вероятно, из-за того, что окно TCP меньше, чем вы хотели бы). Было бы полезно взглянуть на поток данных с помощью Wireshark (в идеале до и после изменений, которые я предлагаю выше).
Увидеть:
- http://msdn.microsoft.com/en-us/library/ms819736.aspx - настройка окна TCP
- http://msdn.microsoft.com/en-us/library/ms740476(VS.85).aspx - setsockopt
- http://en.wikipedia.org/wiki/Transmission_Control_Protocol - управление потоком TCP
- http://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html - остерегайтесь управления потоком TCP при использовании асинхронных сетевых API.
Кажется, что MSDN здесь не очень помогает, за исключением того, что он подтверждает, что TransmitFile должна быть правильной функцией для использования здесь. Вы уже попробовали это?
hFile
Дескриптор открытого файла, который передает функция TransmitFile. Поскольку операционная система последовательно читает данные файла, вы можете улучшить производительность кэширования, открыв дескриптор с помощью FILE_FLAG_SEQUENTIAL_SCAN.
РЕДАКТИРОВАТЬ: Следующим шагом я бы порекомендовал бы проверить, как FileZilla это делает (это с открытым исходным кодом, не так ли?). Возможно, использование Windows API - не идеальный способ сделать это, хотя TransmitFile объявлен как производительная функция.
Я пытался добавить TransmitFile в мой код, но производительность была ужасной. Это будет просто сидеть там двадцать секунд, прежде чем начать загрузку.
Я читал, что он также кажется асинхронным в некотором роде, хотя это нигде не задокументировано. Кроме того, похоже, что это может привести к сбою приложения, если вы выполняете определенные операции в неподходящее время: social.msdn.microsoft.com
Плохая документация и плохая производительность == не использовать, в моей книге. Это две строки C# для загрузки файла в байт [] и записи его в вывод...