Автомат надо сохранить. select без автомата не имеет смысла.
Смысл тут такой: был сервер без select (с одной копией автомата). Надо
сделать массив из структур состояний (т.е. по одному автомату на
соединение), с помощью select выяснить, по какому именно соединению
возможен прием или передача данных, и продвинуть соответствующий ему
автомат.
--
Александр Патраков
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *utimeout);
про readfds все понятно, если по некоторому сокету пришли данные, то с
помощью FD_ISSET узнаем какой именно тот эсокет и обрабатываем,
не ясно про writefds, как select понимает что от нас ждут данных?
> Спасибо, еще вопрос вот в select
>
> int select(int nfds, fd_set *readfds, fd_set *writefds,
> fd_set *exceptfds, struct timeval *utimeout);
>
> про readfds все понятно, если по некоторому сокету пришли данные, то с
> помощью FD_ISSET узнаем какой именно тот сокет и обрабатываем,
> не ясно про writefds, как select понимает что от нас ждут данных?
Он это не понимает. Он только понимает, что в ядре есть незаполненный
буфер и, следовательно, что send() не зависнет. Т.е. мы в writefds
складываем все дескрипторы, куда хотим что-либо записать, а на выходе
из них останутся только те, запись в которые не завесит процесс.
--
Александр Патраков
Не совсем ясен вопрос, но могу отметить следующее:
1. При fork() все файловые дескрипторы остаются и никак не меняются по номеру.
2. Обычно, первые три дескриптора (0, 1 и 2) заняты под stdin, stdout и stderr.
3. Нельзя делать никаких предположений относительно того, какой номер
дескриптора вернётся после вызова accept(). Необходимо писать
программы так, будто этот номер непредсказуем.
4. на самом деле, accept() вернет наименьший по номеру дескриптор из
возможных вариантов.
Если я не ответил на вопрос, то лучше его повторить, но переформулировав.
--
Segmentation fault
> При использовании селекта, допустим я форкнул новый процесс, будет ли
> считаться серверный сокет за первый открытый дескриптор или первыйм
> будет тот, который вернул аксепт?
Марк ответил правильно, но хочу добавить, что при использовании select()
в рамках материала, который пройден на лекциях, отличных от
последней, fork() вместе с select() не вызывается. Поэтому я не совсем
понял, в связи с чем был задан вопрос.
Напомню, что мы проходили:
prefork, process-per-client: вызывается fork(), используются
блокирующие сокеты, не вызывается select(), не используется автоматное
программирование (то, что было на 6-й лекции - это искусственное
упражнение, не имеющее отношения к реальным программам).
select: все соединения обслуживаются с помощью неблокирующих сокетов в
одном процессе, fork() не вызывается, используется автоматное
программирование, select() используется, чтобы выяснить, какой автомат
продвигать. В fd_set'ы на каждом шаге добавляются слушающий сокет (если
он готов для чтения, делаем accept() и добавляем нового клиента в массив
состояний) и все файловые дескрипторы от клиентов (при готовности
продвигаются соответствующие автоматы).
poll, epoll: это улучшенные варианты select(), используются
совершенно аналогично.
Гибридная модель prefork + select (вкратце упоминалась на последнем
занятии): создается слушающий сокет, N раз вызывается fork (как в модели
prefork). В каждом из дочерних процессов реализуется модель с select.
При этом файловый дескриптор от слушающего сокета - единственный общий
дескриптор, являющийся сокетом. Он имеет один и тот же номер, а именно
тот, который вернул socket().
--
Александр Патраков