разбираюсь сейчас с epoll. Для теста навоял простенький echo сервер Все вопросы по ходу кода Код (Text): #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); if ((epfd = epoll_create(EPOLL_SIZE)) != -1) // какое желательное значение ставить для EPOLL_SIZE да и вообще какое максимально возможное { 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_ADD)? // или достаточно просто его закрыть? } 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) появление каких сигналов желательно обрабатывать в данном случае? потому как столкнулся с проблемой - если записать в сокет отключенного клиента, то появляется сигнал об это.
slesh 1) На сколько я понимаю, MAX_EVENTS должно быть равным максимальному количеству клиентов, которых ты собираешься обслуживать единовременно. Так, например, для хттп-сервера, даже с дестками тыщ посетителей в сутки, единовременная нагрузка будет исчисляться единицами. 2) Я бы не мешал бы в кашу многопоточность (в смысле, один клиент - одни поток) с асинхронной работой epoll'a, иначе теряется весь смысл и вся прелесть данного метода. 3) В своей реализации периодически натыкаюсь на ошибку non socket, поэтому, думаю что все-таки стоит, хотя во многих источниках говорится, что достаточно просто закрыть сокет. 4) Оно ограничено допустимым количеством открытых дескрипторов в системе.