FIFO, poll, epoll

Authors: WhoAmI, CrazyMonkey
email: kccddb@gmail.com
Date: 20230513
Copyright: CC BY-NC-SA

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

e.g.,


mkfifo fifo0
mkfifo fifo1


terminal 0:
./poll fifo0 fifo1

terminal 1:

echo "termainal 0" > fifo0
echo "termainal 1" > fifo1

poll:

On success, poll() returns a nonnegative value which is the number of elements in the pollfds whose revents fields have been set to a nonzero value (indicating an event or an error).

A return value of zero indicates that the system call timed out before any file descriptors became read.

​​​​   On error, -1 is returned, and errno is set to indicate the error.

如果 您需要處理
Level-triggered and edge-triggered
或 超過 1024 的 connections

您需要用 Linux 特有的

epoll

epoll_wait

thread 中使用 要特別小心 lock/unlock 的問題!!!

Using epoll() For Asynchronous Network Programming

epoll, epoll_ctl 使用 red-black tree

HW:

epoll() Tutorial – epoll() In 3 Easy Steps!

poll

poll.c

/* * * Based on linux man page: poll_input.c * Licensed under GNU General Public License v2 or later. #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); timeout: milliseconds */ #include <poll.h> #include <fcntl.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) //timout=-1 : infinite timeout #define timeout 10 #define buffersize 255 int main(int argc, char *argv[]) { int nfds, num_open_fds; struct pollfd *pfds; if (argc < 2) { fprintf(stderr, "Usage: %s file...\n", argv[0]); exit(EXIT_FAILURE); } num_open_fds = nfds = argc - 1; pfds = calloc(nfds, sizeof(struct pollfd)); if (pfds == NULL) errExit("malloc"); /* Open each file on command line, and add it 'pfds' array. */ for (int j = 0; j < nfds; j++) { pfds[j].fd = open(argv[j + 1], O_RDONLY); if (pfds[j].fd == -1) errExit("open"); printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd); pfds[j].events = POLLIN; } /* Keep calling poll() as long as at least one file descriptor is open. */ while (num_open_fds > 0) { int ready; printf("About to poll()\n"); //timout=-1 : infinite timeout ready = poll(pfds, nfds, timeout); if (ready == -1) errExit("poll"); printf("Ready: %d\n", ready); /* Deal with array returned by poll(). */ for (int j = 0; j < nfds; j++) { char buf[buffersize+1]; if (pfds[j].revents != 0) { printf(" fd=%d; events: %s%s%s\n", pfds[j].fd, (pfds[j].revents & POLLIN) ? "POLLIN " : "", (pfds[j].revents & POLLHUP) ? "POLLHUP " : "", (pfds[j].revents & POLLERR) ? "POLLERR " : ""); if (pfds[j].revents & POLLIN) { ssize_t s = read(pfds[j].fd, buf, sizeof(buf)-1); if (s == -1) errExit("read"); buf[s]=0; // size_t or ssize_t argument printf(" read %zd bytes: %s\n", s, buf); } else { /* POLLERR | POLLHUP */ printf(" closing fd %d\n", pfds[j].fd); if (close(pfds[j].fd) == -1) errExit("close"); num_open_fds--; } } } } free(pfds); printf("All file descriptors closed; bye\n"); exit(EXIT_SUCCESS); }

epoll

epoll - I/O event notification facility

epoll_create, epoll_create1 - open an epoll file descriptor

epoll_ctl - control interface for an epoll file descriptor

epoll_wait

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);

typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };

The timeout argument specifies the number of milliseconds that epoll_wait() will block.

Specifying a timeout of -1 causes epoll_wait() to block indefinitely, while specifying a timeout equal to zero cause epoll_wait() to return immediately, even if no events are available.

Maxevents is just the length of the struct epoll_events array pointed to by *events

epoll.c

/* Author: WhoAmI * email: kccddb@gmail.com * Licience: GPLv2 * File: epoll.c * / #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h> #define BUFFERLEN 1024 #define perror(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) #define pinfo(msg) do { fprintf(stdout,"%s",msg); } while (0) #define MAX_EVENTS 20 int main(int argc, char *argv[]) { const int EVENTS_SIZE = 20; struct epoll_event ev, epev, events[MAX_EVENTS]; char echo[]="Good!!!!"; char buff[BUFFERLEN]; int socketFd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sockAddr, cli_addr; sockAddr.sin_port = htons(8088); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = htons(INADDR_ANY); if (bind(socketFd, (struct sockaddr *) &sockAddr, sizeof(struct sockaddr)) == -1) { printf( "bind error\n"); return -1; } if (listen(socketFd, 10) == -1) { perror( "listen error"); return -1; } int eFd = epoll_create(1); epev.events = EPOLLIN; epev.data.fd = socketFd; epoll_ctl(eFd, EPOLL_CTL_ADD, socketFd, &epev); while (!0) { int eNum = epoll_wait(eFd, events, EVENTS_SIZE, -1); if (eNum == -1) { perror( "epoll_wait " ); return -1; } for (int i = 0; i < eNum; i++) { if (events[i].data.fd == socketFd) { if (events[i].events & EPOLLIN) { socklen_t length = sizeof(struct sockaddr); int fd = accept(socketFd, (struct sockaddr *) &cli_addr, &length); if (fd > 0) { epev.events = EPOLLIN | EPOLLET; epev.data.fd = fd; int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { printf ("set no block error, fd: %d\n",fd); continue; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { printf("set no block error, fd:" , fd); continue; } //add new connection epoll_ctl(eFd, EPOLL_CTL_ADD, fd, &epev); printf( "client on line fd: %d", fd); } } } else { /* * POLLRDHUP (since Linux 2.6.17) Stream socket peer closed connection, or shut down writing half of connection. The _GNU_SOURCE feature test macro must be defined (before including any header files) in order to obtain this definition. * POLLERR Error condition (only returned in revents; ignored in events). This bit is also set for a file descriptor referring to the write end of a pipe when the read end has been closed. * */ if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) { //remove client fd epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, events); printf( "client out fd: %d\n" ,events[i].data.fd );; close(events[i].data.fd); } else if (events[i].events & EPOLLIN) { int len = read(events[i].data.fd, buff, sizeof(buff)-1); if (len == -1) { epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, events); printf("client out fd: %d\n",events[i].data.fd ); close(events[i].data.fd); } else { buff[len]=0; printf("%s\n",buff); write(events[i].data.fd, echo, sizeof(echo)); } } } } } exit(EXIT_SUCCESS); }
int exec(char *cmd) { FILE *fp; char buffer[256]; fp = popen(cmd, "r"); while(fp){ fgets(buffer, sizeof(buffer), fp); if(!feof(fp)){ printf(">"); printf("%s", buffer); } else{ pclose(fp); return 0; } } pclose(fp); return 0; }

將上面兩段程式結合, 可以 telnet 至 server 執行 命令