例如实现用epoll读三个管道文件:
test.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <stdlib.h>
typedef struct {
char *name;
int fd;
}mydata_t; //每个文件描述符都使用一个结构体变量存放相应的内容
int main(void)
{
mkfifo("/tmp/fifo1", 0644);
mkfifo("/tmp/fifo2", 0644);
mkfifo("/tmp/fifo3", 0644);
int fd1 = open("/tmp/fifo1", O_RDWR);
int fd2 = open("/tmp/fifo2", O_RDWR);
int fd3 = open("/tmp/fifo3", O_RDWR);
if ((fd1 < 0)||(fd3<0)||(fd2<0))
{
printf("open fifo failed\n");
return -1;
}
////////////
int epfd, ret;
epfd = epoll_create1(0); //1. 创建epoll实例
if (epfd < 0)
{
perror("epoll create");
return -1;
}
//2.把要监控的文件描述符加入epfd引用的epoll实例
struct epoll_event evt;
mydata_t *data;
evt.events = EPOLLIN;
data = malloc(sizeof(mydata_t));
data->name = "fifo1";
data->fd = fd1;
evt.data.ptr = data;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd1, &evt); //当fd1可读时,epoll_wait会返回evt里面的内容. 而且epoll_ctl函数会把evt的内容复制一份与fd1对应的
data = malloc(sizeof(mydata_t));
data->name = "fifo2";
data->fd = fd2;
evt.data.ptr = data;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd2, &evt);
data = malloc(sizeof(mydata_t));
data->name = "fifo3";
data->fd = fd3;
evt.data.ptr = data;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd3, &evt);
////////////////////////////////////////////////////
char line[500];
while (1)
{
ret = epoll_wait(epfd, &evt, 1, -1);
if (ret <= 0)
continue;
//直接获取可操作文件描述符对应的epoll_event数据。 本例里是一个对应mydata_t类型的数据,包含有文件名,文件描述符
//不用遍历所有文件描述符了
data = evt.data.ptr;
printf("from %s\n", data->name);
ret = read(data->fd, line, sizeof(line));
line[ret] = 0;
printf("%s\n", line);
}
return 0;
}
///
再如用epoll实现tcp服务器的群发功能:
server.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
typedef struct node {
int fd;
struct node *next, *prev;
}node_t; //用于存放所在客户端连接产生的文件描述符
int main(void)
{
int sd, fd;
sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(7788);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sd, &addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
listen(sd, 1000);
/
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
node_t head = {.next = &head, .prev = &head};
node_t *new, *tmp;
int epfd, num, i, ret;
struct epoll_event evt, ev_ret[10];
char data[500];
epfd = epoll_create1(0);
evt.events = EPOLLIN;
evt.data.fd = sd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sd, &evt);
while (1)
{
num = epoll_wait(epfd, ev_ret, 10, -1);
if (num <= 0)
continue;
for (i = 0; i < num; i++)
{
if (ev_ret[i].data.fd == sd) //有新客户端连接
{
fd = accept(sd, &peer, &len);
if (fd <= 0)
continue;
printf("from %s:%d fd = %d\n", inet_ntoa(peer.sin_addr), htons(peer.sin_port), fd);
new = malloc(sizeof(*new));
new->fd = fd;
new->next = &head;
new->prev = head.prev;
head.prev->next = new;
head.prev = new;
evt.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &evt);
continue;
}
//客户端有发新内容过来
ret = read(ev_ret[i].data.fd, data, sizeof(data));
if (ret <= 0)
{
//客户端端断线
close(ev_ret[i].data.fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, ev_ret[i].data.fd, NULL);
for (tmp = head.next; tmp != &head; tmp = tmp->next)
{
if (tmp->fd == ev_ret[i].data.fd)
break;
}
tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
free(tmp);
continue;
}
data[ret] = 0;
printf("got: %s\n", data);
for (tmp = head.next; tmp != &head; tmp = tmp->next) //往其它客户端转发内容
write(tmp->fd, data, ret);
}
}
return 0;
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
void *thread_func(void *arg);
int main(void)
{
int sd;
sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in to;
to.sin_family = AF_INET;
to.sin_port = htons(7788);
to.sin_addr.s_addr = inet_addr("192.168.250.250");
if (connect(sd, &to, sizeof(to)) < 0)
{
perror("connect");
return -1;
}
char data[500];
int ret;
pthread_t tid;
pthread_create(&tid, NULL, thread_func, &sd);
while (1)
{
ret = read(0, data, sizeof(data));
data[ret] = 0;
write(sd, data, ret);
}
return 0;
}
void *thread_func(void *arg)
{
int sd = *(int *)arg;
int ret;
char data[500];
while (1)
{
ret = read(sd, data, sizeof(data));
if (ret <= 0)
break;
data[ret] = 0;
printf("from server: %s\n", data);
}
return NULL;
}