2009-03-12 9 views
3

Когда мне нужно буферизованное IO при блокировании дескриптора файла, я использую stdio. Но если я превращу файловый дескриптор в неблокирующий режим в соответствии с ручной буферизацией stdio, это непригодно. После некоторых исследований я вижу, что BIO можно использовать для буферизации неблокирующих IO.Как я могу заблокировать неблокирующий IO?

Но могут ли быть другие альтернативы?

Мне нужно это, чтобы избежать использования потоков в среде с несколькими соединениями.

+0

Можете ли вы получить более подробную информацию, например, функции и т. Д., Которые вы используете. – dirkgently

+1

Я второй, этот вопрос очень тяжелый. Я даже не понимаю, как это сформулировано прямо сейчас. – unwind

+0

«Видеть на BIO» означает «читать на блокировке IO»? каков контекст вопроса? – hhafez

ответ

15

Я думаю, что вы говорите, это Reactor Pattern. Это довольно стандартный способ обработки множества сетевых подключений без потоков и очень распространен в многопользовательских игровых серверах. Другая реализация (в python) - twisted matrix.

Основной Алгоритм Построения является:

  • иметь буфер для каждого сокета
  • проверить, какие сокеты готовы для чтения (выберите(), опрос(), или просто итерацию)
  • для каждого сокета :
    • вызов RECV() и накапливать содержимое в буфер сокета до тех пор, пока RECV возвращает 0 или ошибку с EWOULDBLOCK
    • уровня приложения
    • вызова да та обработчик для сокета с содержимым буфера
    • ясно буфера сокета
+0

В описании шаблона реактора я обнаружил libowfat. Это наиболее адекватно для моей потребности в этой теме. БЛАГОДАРЯ –

3

Я вижу, вопрос был отредактирован сейчас и по крайней мере более понятен, чем раньше.

В любом случае, разве это не противоречие?

  • Вы не блокируете ввод-вывод, потому что хотите быстро читать небольшие суммы, обычно жертвуя пропускной способностью для латентности.
  • Вы делаете это буферизированным, потому что вам не важно, что такое латентность, но хотите эффективно использовать подсистему ввода-вывода за счет латентности торговли для пропускной способности.

Выполнение их обоих одновременно представляется противоречием, и его трудно себе представить.

В чем заключаются семантика? Если вы это сделаете:

int  fd; 
char buf[1024]; 
ssize_t got; 

fd = setup_non_blocking_io(...); 
got = read(fd, buf, sizeof buf); 

Какое поведение вы ожидаете, если имеется 3 байта? Блокирование/буферизация ввода-вывода может блокироваться до тех пор, пока вы не сможете больше удовлетворить ваш запрос, а неблокирующий ввод-вывод немедленно вернет 3 доступных байта.

Конечно, если у вас есть протокол сверху, который определяет какую-то структуру сообщений, чтобы вы знали, что «этот ввод-вывод неполный, я не могу разобрать его, пока у меня больше данных», вы может буферизировать его самостоятельно на этом уровне и не передавать данные вверх, пока не будет получено полное сообщение.

+0

Это позволяет мне избегать использования потоков в приложениях с несколькими соединениями. –

+1

Это не противоречие. Неблокирующий ввод-вывод чаще всего используется, когда программе необходимо выполнять другую работу (часто обслуживая другие дескрипторы) и не хочет блокировать какой-либо данный дескриптор. Это несколько иной вид задержки, чем ожидание полного буфера. – dwc

0

Вы можете создать на структуру с упорами для каждого дескриптора файла, а затем накапливают эти буфера до RECV() возвращает 0 или у вас достаточно данных для обработки в вашем буфере.

Если я правильно понял ваш вопрос, вы не можете буферизировать, потому что с неблокированием вы пишете в тот же буфер с несколькими соединениями (если глобально) или просто пишете небольшие фрагменты данных (если они локальны).

В любом случае ваша программа должна быть в состоянии определить, куда поступают данные (возможно, с помощью дескриптора файла) и соответствующим образом буферизировать ее.

Threading также является вариантом, это не так страшно, как многие из них звучат.

1

В зависимости от протокола, безусловно, возможно, что вам нужно будет буферизовать ваши чтения для неблокирующего сетевого узла (клиента или сервера).

Как правило, эти буферы предоставляют несколько индексов (смещений), которые записывают позицию последнего обработанного байта и последнего байта (то есть либо то же, либо больше, чем обработанное смещение). И они также (должны) обеспечивают более богатую семантику уплотнения буфера, прозрачного управления размером буфера и т. Д.

В Java (по крайней мере) неблокирующие сетевые io (NIO) пакеты также предоставляют набор структур данных (ByteBuffer и т. д.), которые направлены на создание общей структуры данных.

Существуют либо такие структуры данных для C, либо вы должны катить их самостоятельно. После этого просто прочитайте как можно больше данных и позвольте буферу управлять такими проблемами, как переполнение (например, чтение байтов через границы фрейма сообщения) и использование смещения маркера для отметки обработанных байтов.

Как указано в Android, вам необходимо (очень вероятно) создать согласованные буферы для каждого открытого соединения.

0

Ryan Dahl's evcom library который делает именно то, что вы хотели.

Я использую его в своей работе, и он отлично работает. Имейте в виду, однако, что он не (пока, но в ближайшее время) имеет асинхронное DNS-разрешение. Райан предлагает udns by Michael Tokarev. Я пытаюсь принять udns вместо блокировки getaddrinfo().