Authors: WhoAmI, CrazyMonkey
email: kccddb@gmail.com
Date: 20230513
Copyright: CC BY-NC-SA
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 特有的
thread 中使用 要特別小心 lock/unlock 的問題!!!
Using epoll() For Asynchronous Network Programming
epoll, epoll_ctl 使用 red-black tree
HW:
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 - I/O event notification facility
epoll_create, epoll_create1 - open an epoll file descriptor
epoll_ctl - control interface for an epoll file descriptor
#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 執行 命令
Authors: WhoAmI, CrazyMonkeyemail: kccddb@gmail.comDate: 20221217Copyright: CC BY-NC-SA
Jun 22, 2025Author: \mathcal{CrazyDog}, Ph.D. in Electrical Engineering, NCTUemail: kccddb@gmail.comDate: 20230910
Jun 22, 2025Authors: CrazyDog, CrazyMonkeyemail: kccddb@gmail.comDate: 20230222
Jun 22, 2025Author: WhoAmI Date: 20230523 email:kccddb@gmail.com Copyright: CC BY-NC-SA 《荀子‧勸學》不積跬步,無以至千里;不積小流,無以成江海。 I. Mutex variables MUST be declared with type pthread_mutex_t, and must be initialized before they can be used. II. 了解 pthread_mutex_lock / pthread_mutex_unlock 與可能問題和代價 III. 程式執行效率與startvation 等問題
Jul 11, 2024or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up