Как буферизовать данные для send () и select ()? - PullRequest
1 голос
/ 15 июня 2009

В то время как send () завершается успешно, все данные отправляются большую часть времени, это не всегда так. Поэтому людям рекомендуется использовать write-fdset для select () и poll (), чтобы проверить, доступен ли для записи сокет.

Как выглядят обычные механизмы для буферизации данных для отправки при сохранении хорошо понятного исходного кода?

Ответы [ 3 ]

1 голос
/ 16 июня 2009

Поскольку мы находимся на земле C ++, вы можете хранить данные в std :: vector

Новые данные добавляются в конец вектора. Когда вы получите уведомление о том, что сокет доступен для записи, попробуйте отправить полный вектор. send () вернет, сколько действительно было отправлено. Затем просто удалите это количество байтов из начала вектора:

std::vector<char> buffer;
...
if( ! buffer.empty() )
{
    int bytesRead = send( socket, &buffer[ 0 ], buffer.size(), flags );
    if( bytesRead > 0 )
        buffer.erase( 0, bytesRead );
    else
       // some error...
}

Так что, возможно, нужно выполнить дополнительную проверку ошибок, но вы поняли идею?

Вместо того, чтобы ставить в очередь каждый отдельный запрос на отправку, преимущество в том, что вы можете потенциально объединить несколько отправок более высокого уровня в одну отправку через сокет, предполагая, что вы используете TCP?

Но, как справедливо заметил Ремус, управление потоком данных и API - это хитрый бит, то есть, как вы можете остановить слишком большой буфер?

1 голос
/ 16 июня 2009

При написании OO, которое должно быть сосредоточено вокруг цикла select () / poll (), вам нужна хорошая абстракция. Я всегда находил класс Reactor с адаптивной средой связи (ACE) очень хорошим для этого. Есть пара книг «Сетевое программирование на C ++» Дуга Шмидта, которые освещают эту среду, а также различные другие вещи в Интернете, включая Проектирование и использование реактора ACE

1 голос
/ 15 июня 2009

Я не очень хорошо знаком со стороной * nix программирования сокетов, но я столкнулся с той же проблемой на стороне Win32. Буферизация не является большой проблемой (вы ставите запросы в очередь и просматриваете завершение записи, чтобы отправить следующую из очереди), реальная проблема заключается в том, что необходимо буферизовать сигналы, которые вы фактически обрабатываете управление потоком, и вы не можете решить управление потоком с одной только буферизацией: всегда может быть потребитель медленнее, чем производитель, и буфер в основном выйдет из-под контроля. Вы должны распространить управление потоком вверх по потоку на любой модуль, производящий данные, и это создает действительно сложные интерфейсы. Все запросы «записи» должны поддерживать коды возврата, указывающие состояние управления потоком (т. Е. «Прекратить запись, места больше нет!») И обратные вызовы, чтобы пригласить вызывающего пользователя возобновить операции записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...