epoll を使用してイベント ベースのサーバーを作成したいと考えています。
各クライアントには個別の要求があり、サーバーはそれらに応答する必要があります。サーバーは接続を待機し、接続が利用可能になると、読み取りのためにキューに入れられます。データはクライアントから読み取られ、書き込みのためにキューに入れられます。データを処理した後、それぞれに適切な応答を送信する必要があります。
すべての操作は非同期になります。
問題は、ソケットが書き込みの準備ができているときに、どの応答がどのソケットに対するものであるかをどのように判断できるかということです?? 1 つの方法として、(ソケット、データ) タプルを格納することはできますが、それは一種の悪いプログラミングです。
各ソケットまたは各 epoll イベントにコンテキストを割り当てて、どのデータがどのソケットに属しているかを判断できるかどうか疑問に思います。
何か案が?
epoll の代わりに SIGIO を使用することに関する提案はありますか? コンテキストをファイル記述子またはシグナルに割り当てることができれば (私は Linux プログラミングに精通していません)、無期限にスリープしてシグナルを待つことができます...
ネットワークのことは忘れて、この例を見てください。事前に作成した FIFO を開き、SIGIO を取得するまでスレッドを一時停止します。別のケースでは、10 個の FIFO を開き、必要なときにそれぞれに乱数を割り当てたとします。その番号をコンソールに出力します。どういうわけか、番号を取得できる必要があります。おそらく、ファイル記述子にコンテキストを割り当てることができますか?
#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;
}
少し変更しました:
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;
...
奇妙なセグメンテーション違反が発生します。
FreeBSD の「mac_set_fd(int fd, mac_t label);」この問題に関連しています。