I want to write an event based server using epoll.
each client has a distinct request, and the server should respond to them. the server will wait for connections, and when connections are available they're queued for read. data is read from the clients and they'll be queued for write. after processing the data, an appropriate response should be sent to each.
all the operations will be asynchronously.
the problem is, how can I determine, which response is for which socket when the sockets are ready for writing?? one way, I can store a (socket, data) tuple, but it's kind of bad programming.
I wonder if I could assign a context to each socket, or each epoll event, so I could determine which data belongs to which socket.
any idea?
is there any suggestions on using SIGIO instead of epoll? if I could assign a context to a file descriptor, or to a signal (I'm not familiar with linux programming) then I could sleep indefinitely and wait for signals...
now forget about networking, look at this example, I open a pre-created FIFO, and pause the thread till I get a SIGIO, in another case, consider I opened 10 FIFO s and assigned a random number to each, when I want to print that number to console, somehow I must be able to retrieve the number, maybe I can assign a context to the file descriptor?
#include <stdlib.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
static void sigioHandler(int sig)
{
}
int main()
{
int fd, epfd, ret, i, nr_events, flags;
struct sigaction sa;
struct epoll_event event, *events;
char buf[10];
memset(buf, 0, 10);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sigioHandler;
if (sigaction(SIGIO, &sa, NULL) == -1)
{
perror("sigaction");
exit(1);
}
events = malloc (sizeof (struct epoll_event) * 10);
if (!events) {
perror ("malloc");
return 1;
}
fd = open("/tmp/foo", O_RDONLY);
if(fcntl(fd, F_SETOWN, getpid())==-1){
perror("own");
exit(1);
}
flags = fcntl(fd, F_GETFL);
if(fcntl(fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK)==-1){
perror("set");
exit(1);
}
read(fd, buf, 10);
epfd = epoll_create(10);
if(epfd<0)
perror("epoll_create");
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
if(ret)
perror("epol_ctl");
while(1){
pause();
nr_events = epoll_wait (epfd, events, 10, -1);
if (nr_events < 0) {
perror ("epoll_wait");
free (events);
return 1;
}
for (i = 0; i < nr_events; i++) {
if(events[i].events & EPOLLIN)
{
read(events[i].data.fd, buf, 10);
if(buf[0] == '#')
goto end;
printf("%s", buf);
}
}
}
end:
free (events);
close(epfd);
close(fd);
return 0;
}
changed it a little bit:
static void sigioHandler(int status, siginfo_t *ioinfo, void * context)
{
if(ioinfo == NULL)
return;
switch (ioinfo->si_code)
{
case POLL_IN:
printf("signal received for input chars.sig:%d -%d\n",status, ioinfo->si_code);
break;
case POLL_OUT:
default:
printf("signal received for something else.sig:%d -%d\n",status, ioinfo->si_code);
break;
}
}
in main:
...
sa.sa_sigaction = sigioHandler;
...
I get a strange Segmentation Fault.
don't know if FreeBSD's "mac_set_fd(int fd, mac_t label);" is related to this problem.