Разбираюсь сейчас с 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;
}