Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> использование epoll, парочка вопрос по использованию epoll 
:(
    Опции темы
slesh2000
Дата 24.6.2010, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 24.5.2010

Репутация: нет
Всего: нет



Разбираюсь сейчас с epoll. Для теста навоял простенький echo сервер
Все вопросы по ходу кода (в комментариях)

Код

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>


#define SERVER_ADDR INADDR_ANY
#define SERVER_PORT 12345
#define MAX_EVENTS  100
#define EPOLL_SIZE  100


int SetNonBlocking(int sock)
{
    int ret = -1;
    int opts = fcntl(sock, F_GETFL);

    if (opts >= 0)
    {
        opts = (opts | O_NONBLOCK);
        if (fcntl(sock, F_SETFL, opts) >= 0)
        {
            ret = 0;
        }
    }

    return ret;
}

int main()
{
    int MainSock;
    struct sockaddr_in saddr;
    int x;
    int cnt;
    int len;
    int epfd;
    struct epoll_event ev;
    struct epoll_event events[MAX_EVENTS];
    char buf[256];
    int Work = 1;

    MainSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (MainSock != -1)
    {
        saddr.sin_family = AF_INET;
        saddr.sin_addr.s_addr = SERVER_ADDR;
        saddr.sin_port = htons(SERVER_PORT);
        x = 1;
        setsockopt(MainSock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
        if (bind(MainSock, (struct sockaddr*) &saddr, sizeof (struct sockaddr_in)) != -1)
        {
            listen(MainSock, 100);
            // какое желательное значение ставить для EPOLL_SIZE.
            // да и вообще какое максимально возможное?
            // в одних источниках пишется что задается максимальное
            // в других что желаемое (но не предельное)
            if ((epfd = epoll_create(EPOLL_SIZE)) != -1)  
            {
                ev.events = EPOLLIN;
                ev.data.fd = MainSock;
                // какое максимальное кол-во может быть добавлено сокетов?
                // по описанию - неограниченное. Но всё же лимиты должны быть
                // или пока есть память?
                if (epoll_ctl(epfd, EPOLL_CTL_ADD, MainSock, &ev) != -1)
                {
                    while (Work)
                    {
                        // может ли следующий участок вызвать ошибку при большой загруженности
                        // или же он вызывает ошибку только в реально плачевном случае
                        // когда уже ничего не исправишь?
                        if ((cnt = epoll_wait(epfd, events, MAX_EVENTS, -1)) == -1)
                        {
                            Work = 0;
                        }

                        for (x = 0; x < cnt; x++)
                        {
                            if (events[x].data.fd == MainSock) // if new client
                            {
                                ev.data.fd = accept(MainSock, NULL, 0);
                                if (ev.data.fd == -1)
                                {
                                    Work = 0;
                                }
                                else
                                {
                                    SetNonBlocking(ev.data.fd);
                                    // какие желательно обрабатывать события?
                                    // если необходимо сервер только отвечает на запросы клиента (т.е. сам не шлет данные пока их не запросят)
                                    ev.events = EPOLLIN | EPOLLET;

                                    if (epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
                                    {
                                        close(ev.data.fd);
                                    }
                                }
                            }
                            else // if clients event
                            {
                                if (events[x].events & EPOLLIN) // if client sended data
                                {
                                    len = recv(events[x].data.fd, buf, 256, 0);
                                    if (len > 0)
                                    {
                                        if (!strncmp(buf, "EXIT", 4))
                                        {
                                            send(events[x].data.fd, "CLOSED\n", 7, 0);
                                            close(events[x].data.fd);
                                            // надо ли тут удалять сокет из epfd (через EPOLL_CTL_DEL)?
                                            // или достаточно просто его закрыть?
                                        }
                                        else
                                            if (!strncmp(buf, "TERM", 4))
                                        {
                                            Work = 0;
                                        }
                                        else
                                        {
                                            send(events[x].data.fd, buf, len, 0);
                                        }
                                    }
                                    else // client disconnected
                                    {
                                        close(events[x].data.fd);
                                        // аналогично вышеуказанному вопросу
                                    }
                                }
                                else if (events[x].events & (EPOLLHUP | EPOLLERR)) // if client error
                                {
                                    close(events[x].data.fd);
                                    // аналогично вышеуказанному вопросу
                                }
                            }
                        }
                    }
                }
                close(epfd);
                // должен ли я тут закрывать все сокеты которые были добавлены ранее?
                // или закрытие epfd автоматически вызовет это??
            }
            close(MainSock);
        }
    }

    return 0;
}

И парочка вопросов дополнительных:
1) какое наиболее оптимальное значение для MAX_EVENTS может быть, если учесть что сервер должен обрабатывать много клиентов сразу и много данных передавать (при этом вычисления минимальны)
2) echo сервер это довольно простой вариант, а если требуется более сложные вычисления которые требуют распараллеливание запросов клиентов. т.е. допустим клиент послал запрос, сервер обработал его и ответил. Какая схема многопоточности подойдет?
Вообще в голову пришла идея чтобы как только пришли данные от клиента, так сразу запускать поток для обработки или же уже иметь предварительно запущенные потоки которые ожидают вызова? Или же для linux систем чуть по другому всё?
При этом fork недопустим в данном случае из-за особенностей обработки данных.
3) что можно еще использовать для увеличения скорости работы с сетью. Помимо TCP_NODELAY
4) появление каких сигналов желательно обрабатывать в данном случае?
потому как столкнулся с проблемой - если записать в сокет отключенного клиента, то появляется сигнал об это.
5) как я понял при добавлении сокета в структуре epoll_event поле fd используется для удобства, а на реале я могу в ptr записать адрес структуры, которая более детально описывает клиента?
6) на Windows системах для автоматической проверки соединения использовал функцию WSAIoctl с флагом SIO_KEEPALIVE_VALS, т.е. при не активности клиента автоматически система посылала пустой пакет с данными на который клиент должен был ответить, по прошествии таймауте (если не было ответа) то соединение считалось потеряным. Если подобие такой функции на Linux системах?
7) перед закрытием сокета, надо ли его переводить обратно в блокируемый режим?
PM MAIL   Вверх
MAKCim
Дата 24.6.2010, 15:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
// какое желательное значение ставить для EPOLL_SIZE.

предположительно максимальное число клиентов
однако этот параметр все равно в текущей реализации не используется, так что по факту - любое количество

Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
// какое максимальное кол-во может быть добавлено сокетов?

ограничено памятью


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
// может ли следующий участок вызвать ошибку при большой загруженности

ошибки могут быть, причем вполне стандартные типа EINTR 
ничего критичного здесь нет


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
// какие желательно обрабатывать события?

+EPOLLRDHUP если хочешь отловить момент, когда клиент завершает соединение
ну и плюс, ты уверен, что не понадобится EPOLLOUT? т. е. все данные, отсылаемые клиенту, уйдут за одну операцию?


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
// или достаточно просто его закрыть?

достаточно закрыть через close()


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
/ должен ли я тут закрывать все сокеты которые были добавлены ранее?

должен


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
2) echo сервер это довольно простой вариант, а если требуется более сложные вычисления которые требуют распараллеливание запросов клиентов. т.е. допустим клиент послал запрос, сервер обработал его и ответил. Какая схема многопоточности подойдет?

1 аккептор (тот, что слушает сокет в ожидании клиентов)
N рабочих потоков, каждый со своим epoll (N = числу процессоров/ядер на тачке)


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
3) что можно еще использовать для увеличения скорости работы с сетью. Помимо TCP_NODELAY

потюнить можно через /proc/sys/net, более детально смотри соответствующий ман


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
4) появление каких сигналов желательно обрабатывать в данном случае?
потому как столкнулся с проблемой - если записать в сокет отключенного клиента, то появляется сигнал об это.

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


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
5) как я понял при добавлении сокета в структуре epoll_event поле fd используется для удобства, а на реале я могу в ptr записать адрес структуры, которая более детально описывает клиента?

да


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
6) на Windows системах для автоматической проверки соединения использовал функцию WSAIoctl с флагом SIO_KEEPALIVE_VALS, т.е. при не активности клиента автоматически система посылала пустой пакет с данными на который клиент должен был ответить, по прошествии таймауте (если не было ответа) то соединение считалось потеряным. Если подобие такой функции на Linux системах?

man 7 tcp


Цитата(slesh2000 @  24.6.2010,  13:45 Найти цитируемый пост)
7) перед закрытием сокета, надо ли его переводить обратно в блокируемый режим? 

нет


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0633 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.