LINUX.ORG.RU

select() + FD_ISSET()


1

1

Следающий код:

        // основное тело программы (main)
        FD_ZERO(&rfds);
        FD_SET(ClientSockets[FreeSocketIndex + 1], &rfds);
        if (nfds < ClientSockets[FreeSocketIndex + 1]) nfds = ClientSockets[FreeSocketIndex + 1];
        FreeSocketIndex++;

        // нить, которая обменивается через эти сокеты
        while (TRUE)
        {
                for (socketIndex = 0; socketIndex < FreeSocketIndex; socketIndex++)
                {
                        FD_ZERO(&rfds);
                        FD_SET(ClientSockets[socketIndex], &rfds);
                }
                tv.tv_sec = 0; // wait for five seconds
                tv.tv_usec = 500000;
                result = select(nfds + 1, &rfds, NULL, NULL, &tv);
                if (result && (result != -1))
                {
                     ....
                }
                else {
                        printf("ignore ...\n");
                }
        }
Какие есть косяки в коде?

★★★★★

Нет объяления переменных. :)
И main().

hbars ★★★★★ ()

А вообще, если не шибко нагруженная штука и просто слушать сокет, для этого есть unixway - xinetd.

hbars ★★★★★ ()

Ещё один вопрос. Как отслеживать закрытие соединения клиентами?
(Выше приведен код сервера)

pacify ★★★★★ ()
Ответ на: комментарий от hbars

если не шибко нагруженная штука

нужна максимальная производительность на select()

pacify ★★★★★ ()

главный косяк: зачем городить велосипед? Юзай libev.

это помимо того что у тебя весьма странная работа с индексами. Рано или поздно FreeSocketIndex перевалит за размеры массива.

Закрытие (не обрыв соединения, это другое) клиентом сокета определяется по пустому recv() на сокете. Это и многое другое можно узнать из man recv, man select, man epoll, etc.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

главный косяк: зачем городить велосипед? Юзай libev.

начал писать - надо закончить :)

У меня почему-то select() всегда возвращает значение 1 (число дескрипторов в fd_set для read). Вне зависимости от числа подключенных клиентов.

Весь код сюда выкладывать не стал, не хочу позориться :)

P.S. массив у меня наращивается через realloc()

pacify ★★★★★ ()

всё. Ошибку разглядел. FS_ZERO() выполнялся в цикле, поэтому в rfds заносился только последний дескриптор. На который и реагировал select().

pacify ★★★★★ ()
Ответ на: комментарий от beastie

1. Готов один - потому что я обнулял fd_set каждый раз перед добавлением нового дескриптора. Протупил при написании кода.

2. Спасибо, годная книжка. Позже почитаю, когда отдохну.

3. Сейчас попробовал нагрузить select-сервер с блокирующим read/write десятком клиентов. Получил суммарную скорость
обмена 8-байтными структурами = 12к запросов на клиента. То есть, в сумме - 120к read() + 120к write() в секунду.
Попробовал увеличить число клиентов до 20-ти - сервер быстрее работать не стал. То есть, это - предельная скорость
через loopback для такого способа.

pacify ★★★★★ ()

Какие есть косяки в коде?

Самый фатальный: select не может работать с файловыми дескрипторами, значения которых больше, чем с FD_SETSIZE (1024 в Linux).

red_eyed_peguin ()
Ответ на: комментарий от red_eyed_peguin

select не может работать с файловыми дескрипторами , значения которых больше, чем с FD_SETSIZE (1024 в Linux).

Офигеть. А какая альтернатива под Linux есть, несложная для изучения? poll?

Под виндой тоже такие жесткие ограничения для select()?

pacify ★★★★★ ()
Ответ на: комментарий от pacify

Под виндой тоже такие жесткие ограничения для select()?

Да, ограничение существует во всех системах, но за размер FD_SETSIZE под виндой не ручаюсь. poll — если активных дескрипторов немного, epoll, если много. Также можно лучше сразу взять libev или libevent, если программа состоит, в основном, из цикла обработки событий.

red_eyed_peguin ()

Косяк - select. Давно нужно переходить на epoll, kqueue и остальное. А лучше asio или libev

vertexua ★★★★★ ()
Ответ на: комментарий от pacify

начал писать - надо закончить :)

Не-не, у select банально ниже масштабируемость.

vertexua ★★★★★ ()

Если позволите, то я немного добавлю...

Косяки, судя по всему, Вы уже и сами нашли. :)

С другой стороны.

FD_SETSIZE (1024 в Linux).

Отчасти это так. Если выполнить: grep «#define __FD_SETSIZE» /usr/include/*.h /usr/include/*/*.h, то получим /usr/include/linux/posix_types.h:#define __FD_SETSIZE 1024

С этим бороться можно, но не нужно. В принципе, можно сделать по-грязненькому — #define __FD_SETSIZE 65535, получим предупреждение, но ни чего фатального. Далее нам надо будет глянуть вывод ulimit. В некоторых случаях может быть ограничение и тогда его корректируем ulimit -n 65535, либо unlimited и тогда корректировать не нужно.

Можно глянуть cat /proc/sys/fs/file-max и поправить через sysctl -w fs.file-max=65535

Чтобы не получать предупреждений (малость по-чище, но всё же грязновато), можно написать

#ifdef FD_SETSIZE
#undef FD_SETSIZE
#define FD_SETSIZE 65535
#endif 
и успокоиться.

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

Вдобавок, если надо «кросс-платформеннинько», то тут с оффтопом надо помнить о «нестандартном» поведении select(). http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx

nfds [in] Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.

Вот так вот. Сам как-то промучался.

нужна максимальная производительность на select()

Одно из двух тут лишнее. Либо одно, либо другое. Во-первых, Вам порекомендовали Beej's Guide to Network Programming. Это очень хорошая книга. Но я бы ещё предложил посмотреть http://www.kegel.com/c10k.html

poll?

Не фонтан. Он слегка лучше select. По крайней мере, он не имеет такого жёсткого ограничения на число просматриваемых дескрипторов как у select(), но он выполняет просмотр всех[/] дескрипторов при каждой проверке (чтении).

Гораздо лучше уже упоминавшийся здесь epoll(). У него есть очевидные плюсы — резко повышается скорость работы и нет ограничения на число используемых fd. Задаваемые изначально значения числа дескрипторов носят «рекомендательный» характер и число может быть увеличено при необходимости. Хотя, границы всё-таки есть. Смотрим на cat /proc/sys/fs/epoll/max_user_watches и видим 328310.

Но тут есть несколько подводных камней. Во-первых, из опыта, я напарывался на странное (но крайне редкое) поведение при использовании epoll() через libevent и libev и работе по http. Проблема была в подвисании при закрытии соединения. Я глубоко с этим не копался, просто стал использовать epoll() без покрышек в виде библиотек. Возможно, дело в реализации библиотек или моём фиговом их использовании.

Во-вторых, в оффтопе маловероятно что можно что-то сделать в обход win api, от него там ещё ни кто не уходил. По этой причине там всё сделано «как обычно» и функции, которые реализованы в библиотеках являлись (тогда, когда их смотрел) просто обёрткой над существующей Windows Sockets 2 Architecture (WSA). Сомневаюсь в том, что что-то радикально изменилось. Так что ни о каком росте производительности под оффтопом и не мечтайте.

В третьих, Ваш код может серьёзно измениться при использовании epoll(). ;)

mr_noone ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.