Страница 188 из 399
67 }
68 }
69 }
70 exit(0);
71 }
39-55 Теперь мы анализируем каждый элемент массива структур file, чтобы определить, какие дескрипторы нужно обрабатывать. Если установлен флаг F_CONNECTING и дескриптор включен либо в наборе чтения, либо в наборе записи, неблокируемая функция co
56-67 Если установлен флаг F_READING и дескриптор готов для чтения, мы вызываем функцию read. Если соединение было закрыто другим концом, мы закрываем сокет, устанавливаем флаг F_DONE, выключаем дескриптор в наборе чтения и уменьшаем число активных соединений и общее число соединений, требующих обработки.
Есть два способа оптимизации, которые мы не используем в этом примере (чтобы не усложнять его еще больше). Во-первых, мы можем завершить цикл for в листинге 16.13, когда мы обработали число дескрипторов, которые, по сообщению функции select, были готовы. Во-вторых, мы могли, где это возможно, уменьшить значение maxfd, чтобы функция select не проверяла биты дескрипторов, которые уже сброшены. Поскольку число дескрипторов, используемых в этом коде, в любой момент времени, вероятно, меньше 10, а не порядка тысяч, вряд ли какая-либо из этих оптимизаций стоит дополнительных усложнений.
Эффективность одновременных соединений
Каков выигрыш в эффективности при установлении множества одновременных соединений? В табл. 16.1 показано время, необходимое для выполнения определенной задачи, которая состоит в том, чтобы получить от веб-сервера домашнюю страницу и девять картинок. Время обращения RTT для данного соединения с сервером равно приблизительно 150 мс. Размер домашней страницы — 4017 байт, а средний размер девяти файлов с изображениями составил 1621 байт. Размер сегмента TCP равен 512 байт. Для сравнения мы также представляем в этой таблице значения для многопоточной версии данной программы, которую мы создаем в разделе 26.9.
Таблица 16.1. Время выполнения задания для разного количества одновременных соединений в разных версиях программы