linux下的epoll编程应用


例如实现用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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值