Я пишу программу на C ++, которая просто получает данные с другого компьютера и записывает их в RAID-массив SSD с высокой пропускной способностью (около 100 МБ / с со времени GbEthernet).
Я настроил 2 overlapped_io
каждый, который получен из Ethernet и записан на SSD.
Когда получение будет сделано, он отправит сообщение автору.
И я пользуюсь FILE_NO_BUFFERING_FLAG
при создании файла на диске.
На стороне сетевого отправителя я использую перекрывающийся ввод-вывод для отправки данных.
Я застрял в проблеме: при получении из розетки rv = recv()
не выравнивается с диском (может быть, 4096 раз?).
Что я должен делать?
recv
и небуферизованные записи не очень совместимы друг с другом. Можно заставить это работать, но это потребует немного дополнительной работы.
При выполнении небуферизованных записей, и то и другое начальный адрес вашего буфера и сумма для записи должны быть кратны размеру сектора (см. MSDN). Выравнивание буфера тривиально, но имеет дело с тем, что recv
может вернуть практически любой объем данных (вплоть до объема, который вы запрашиваете, но теоретически это может быть всего 1 байт), это немного работы.
Другая проблема заключается в том, что хотя в значительной степени гарантируется, что размер сектора является степенью двойки (хотя, по крайней мере, использовал к существуют жесткие диски с неэнергетическими секторами в 1990-х, этот факт был скрыт контроллером) ты не знаешь что это такое. И даже если бы вы знали, это может быть иначе на следующем компьютере. Это может быть 512 или 1024 или что-то еще.
Как справиться с этим? Большинство программистов прибегают к простому использованию функции, которая выделяет целые страницы памяти, такие как VirtualAlloc
или анонимное отображение памяти. Так как они работают на страницах, они обязательно выровнены по размеру страницы, что (обычно) означает 4096 байт1.
Поскольку объем записываемых данных также должен быть кратным размеру сектора (но объем полученных данных, вероятно, не равен), у вас есть округление вниз, частичная запись и сохранение оставшейся части для следующей записи.
Опять же, проблема в том, что вы не знаете размер сектора, поэтому лучшее, что вы можете сделать, это округлить до той же степени детализации, которую вы используете для запуска буфера (все остальное будет бессмысленным). Другими словами, вы концептуально должны сделать что-то вроде этого:
while(rv < 0xffff) // don't have enough yet
receive_more_and_append();
num_write = rv & ~0xffff;
rv -= num_write;
memcpy(other_buf, buf+num_write, rv);
WriteFileEx(...);
1Это только половина правды, поскольку Windows имеет минимальную гранулярность выделения 64 КБ. Вы не можете выделить что-то меньшее, чем 64 КБ, и оно не может быть выровнено меньше, чем 64 КБ. Таким образом, на самом деле вы хороши для секторов размером до 64 КБ, что больше, чем все, что вы, вероятно, когда-либо встретите, реально.
Кроме того, в качестве небольшого придирки у Itanium есть 8 тыс. Страниц, а не 4 тыс., Но это не проблема, на самом деле это лучше.