Giriş
Şu satırı dahil ederiz.
Kullanım
1. epoll_create() ile bir epollfd yarat
2. epoll_event yapısını socket fd ile doldur ve epoll_ctl() ile izlemeye başla
3. Döngü içinde epoll_wait metoduu sürekli çağır
4. Event tipine bakarak (EPOLLERR,EPOLLHUP,EPOLLIN,EPOLLOUT) socketler üzerinde işlem yap
5. Ya da socket fd'ye bakarak fd ile işlem yap. Bu yöntem sadece bir kerelik cevap veren sunucu yazılımlarda kullanılabilir.
Tasarım Hatası
epoll tasarım hatası ile ilgili bir açıklama şöyle. Bu yazıyı ilk kez bu sorudaki linkte gördüm. Kısaca dup ile çoklanan bir file descriptor close() metodu ile kapatılsa bile epoll açısından kapanmadığı için halen event'leri bildiriyor diyor.
Örnek ver
2. epoll_create1 metodu - flags
Örnek
Şöyle yaparız.
Şöyle yaparız.
4. epoll_event yapısıŞöyle tanımlarız.
Şu değerlerden birisi olabilir
Şu satırı dahil ederiz.
#include <sys/epoll.h>
epoll neden Önemli
Açıklaması şöyle
2002 — LINUX releases epoll APIThe 2.5.44 release of LINUX included a new API: epoll. The epoll API delivered effectively constant socket look-up time. If networking software used epoll and multiplexed connections across a handful of threads at most (as opposed to 1 thread per request), one could expect significantly better resource utilization on a server and handle 10K simultaneous connections well. This solution reduced the latency of packet routing within Linux, which enabled better scalability of open connections.
1. epoll_create() ile bir epollfd yarat
2. epoll_event yapısını socket fd ile doldur ve epoll_ctl() ile izlemeye başla
3. Döngü içinde epoll_wait metoduu sürekli çağır
4. Event tipine bakarak (EPOLLERR,EPOLLHUP,EPOLLIN,EPOLLOUT) socketler üzerinde işlem yap
5. Ya da socket fd'ye bakarak fd ile işlem yap. Bu yöntem sadece bir kerelik cevap veren sunucu yazılımlarda kullanılabilir.
Tasarım Hatası
epoll tasarım hatası ile ilgili bir açıklama şöyle. Bu yazıyı ilk kez bu sorudaki linkte gördüm. Kısaca dup ile çoklanan bir file descriptor close() metodu ile kapatılsa bile epoll açısından kapanmadığı için halen event'leri bildiriyor diyor.
epoll is broken because it mistakes the "file descriptor" with the underlying kernel object (the "file description"). The issue shows up when relying on the close() semantics to clean up the epoll subscriptions.1. epoll_create metodu - size
epoll_ctl(EPOLL_CTL_ADD) doesn't actually register a file descriptor. Instead it registers a tuple1 of a file descriptor and a pointer to underlying kernel object. Most confusingly the lifetime of an epoll subscription is not tied to the lifetime of a file descriptor. It's tied to the life of the kernel object.
Due to this implementation quirk calling close() on a file descriptor might or might not trigger epoll unsubscription. If the close call removes the last pointer to kernel object and causes the object to be freed, then it will cause epoll subscription cleanup. But if there are more pointers to kernel object, more file descriptors, in any process on the system, then close will not cause the epoll subscription cleanup. It is totally possible to receive events on previously closed file descriptors.
Örnek ver
2. epoll_create1 metodu - flags
Örnek
Şöyle yaparız.
int epollfd = epoll_create1(0);
if (epollfd == -1)
{
perror ("epoll_create");
...
}
ÖrnekŞöyle yaparız.
int efd = epoll_create1 (EPOLL_CLOEXEC);
3. epoll_ctl metoduepoll_ctl metodu yazısına taşıdım
4. epoll_event yapısı
struct epoll_event events[MAXEVENTS];
events AlanıŞu değerlerden birisi olabilir
EPOLLIN
EPOLLIN = 1 ise oku
EPOLLRDHUP
EPOLLRDHUP = 1 ise kapat. EPOLLRDHUP açıklamasını buradan aldım.
EPOLLRDHUP (since Linux 2.6.17)Stream socket peer closed connection, or shut down writing half of connection. (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.)
Örnek
Şöyle yaparız.
epoll_data tipindendir
epoll_data yapısı
epoll_event yapısının bir alanıdır. İçi şöyledir.
fd alanını kullanmak için şöyle yaparız.
ptr alanını kullanmak için bir ata sınıf tanımlarız.
Şöyle yaparız.
Sonucu dolaşmak için şöyle yaparız.
Şöyle yaparız.
int servFd = socket (...);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP;
epollEvt.data.u32 = servFd;
data Alanıepoll_data tipindendir
epoll_data yapısı
epoll_event yapısının bir alanıdır. İçi şöyledir.
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
Örnekfd alanını kullanmak için şöyle yaparız.
epoll_event ev;
ev.data.fd = timerfd;
Örnekptr alanını kullanmak için bir ata sınıf tanımlarız.
class EventHandler {
public:
virtual ~EventHandler() = default;
virtual int fd() const = 0;
virtual void fire() = 0;
};
Bu ata sınıfı ptr alanına vererek epoll() çağrısına dahil ederiz.EventHandler* handler = new TimerHandler();
ev.data.ptr = handler;
epoll_ctl(epollfd, EPOLL_CTL_ADD, handler->fd(), &ev);
Sonuçları dolaşırken şöyle yaparızint n = epoll_wait (epollfd, events , num_events, -1 );
for (int i = 0; i < n; ++i) {
static_cast<EventHandler*>(events[i].data.ptr)->fire();
}
5. epoll_wait metoduŞöyle yaparız.
int n = epoll_wait (epollfd, events, MAXEVENTS, -1);
Örnek
Sonucu dolaşmak için şöyle yaparız.int n = epoll_wait (epollfd, events , num_events, -1 );
for (int i = 0; i < n; ++i) {
if (events[i].data.fd == timerfd) {
handle_timer_callback();
}
else {
// something else
}
}
ÖrnekSonucu dolaşmak için şöyle yaparız.
for (i = 0; i < n; i++)
{
int fd = events[i].data.fd;
if ((events[i].events & EPOLLERR) ||
(events[i].events & EPOLLHUP))
{
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
close(fd);
}
else if (fd == listendf && (events[i].events & EPOLLIN))
{
/* We have a notification on the listening socket, which
means one or more incoming connections. */
HandleAccept(epollfd, listenfd);
}
else if(events[i].events & EPOLLIN)
{
/* We have data on the fd waiting to be read. Read and
display it. We must read whatever data is available
completely, as we are running in edge-triggered mode
and won't get a notification again for the same
data. */
HandleRead(epollfd, fd);
}
else if (events[i].events & EPOLLOUT)
{
...
}
}
ÖrnekŞöyle yaparız.
for (;;) {
struct epoll_event pollEvent[512];
int eventCount = epoll_wait (efd, pollEvent, 512, -1);
for (int i = 0; i < eventCount; ++i) {
struct epoll_event* curEvent = &pollEvent[i];
if (curEvent->data.u32 == servFd) {
int clientFd = accept4 (servFd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
epollEvt.data.u32 = clientFd;
epoll_ctl (efd, EPOLL_CTL_ADD, clientFd, &epollEvt);
continue;
}
int clientFd = curEvent->data.u32;
char recvBuffer[2048];
recvfrom (clientFd, recvBuffer, 2048, 0, NULL, NULL);
char sndMsg[] = "...";
size_t sndMsgLength = sizeof (sndMsg) - 1;
struct iovec sndBuffer;
sndBuffer.iov_base = sndMsg;
sndBuffer.iov_len = sndMsgLength;
writev (clientFd, &sndBuffer, 1);
close (clientFd);
}
}
Hiç yorum yok:
Yorum Gönder