linux epoll监听套接字实例


linux epoll机制用于IO多路复用,能够同时监听多个接字,使用起来比较简单。

相关接口:

       #include <sys/epoll.h>

       int epoll_create(int size);
       int epoll_create1(int flags);	//创建epoll实例
       
       int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);    //添加、删除或修改epoll监听描述符
       
       int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);//监听事件发生

其中epoll_ctl参数op有如下选项:分别对应添加、删除、修改

EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL
             //结构体,在添加到epoll中去的时候可以传递参数,参数可以是指针
           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 */
           };


下面给出一个简单的使用例子,在例子中创建了两个套接字,分别监听不同的端口,将两个套接字添加到epoll中,每当套接字上有读事件发生的时候,就可以进行处理。

/*
 *  Description : linux IO多路复用epoll实例
 *  Date        :20180605
 *  Author      :mason
 *  Mail        : mrsonko@126.com
 *
 */

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define BUFFER_SIZE 512
#define log(fmt, arg...) printf("[udptest] %s:%d "fmt, __FUNCTION__, __LINE__, ##arg)

void main(){
    int fd1, fd2, efd, fds, i, fd;
    int ret, addr_len;
    struct epoll_event g_event;  // epoll事件
    struct epoll_event *epoll_events_ptr; 
    char buffer[BUFFER_SIZE] = {0};
    struct sockaddr_in addr1, addr2;

    // 创建套接字1
    fd1 = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd1 == -1) {
        log("create socket fail \r\n");
        return ;
    }  
    
    // 创建套接字2   
    fd2 = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd2 == -1) {
        log("create socket fail \r\n");
        close(fd1);
        return ;
    }   

    // 设置监听地址,不同套接字监听不同的地址
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = INADDR_ANY; 
    addr1.sin_port = htons(3500);

    addr2.sin_family = AF_INET;
    addr2.sin_addr.s_addr = INADDR_ANY; 
    addr2.sin_port = htons(3501);
    
    addr_len = sizeof(struct sockaddr_in);
    // 套接字绑定地址
    if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) {
        log("bind local listening addr fail,errno : %d \r\n", errno);
        goto err;
    }

    if (0 != bind(fd2, (struct sockaddr *)&addr2, sizeof(struct sockaddr_in))) {
        log("bind local listening addr fail,errno : %d \r\n", errno);
        goto err;
    }

    //创建epoll实例
    efd = epoll_create1(0);
    if (efd == -1) {
        log("create epoll fail \r\n");
        goto err;

    }
    log("create epoll instance success \r\n");
    
    epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
    if (epoll_events_ptr == NULL) {
        log("calloc fail \r\n");
        goto err;
    }

    //添加套接字到epoll中,并监控读事件
    //注意这里传给epoll的参数中可以是指针
    g_event.data.fd = fd1; 
    g_event.events = EPOLLIN;
    epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);          
    
    g_event.data.fd = fd2; 
    g_event.events = EPOLLIN;
    epoll_ctl(efd, EPOLL_CTL_ADD, fd2, &g_event);  

    //监听epoll事件
    while(1) {
        log("Starting waiting epoll event \n");
        fds = epoll_wait(efd, epoll_events_ptr, 2, -1); //阻塞
        for (i = 0; i<fds; i++)
        {    
            fd = epoll_events_ptr[i].data.fd;
            if (epoll_events_ptr[i].events & EPOLLIN)
            {   
                ret = read(fd, buffer, BUFFER_SIZE);
                if(ret != -1)
                    log("recv msg : %s \n", buffer);
                    
            }     
            memset(buffer, 0, BUFFER_SIZE);
        }        
    }   

    
err:
    close(fd1);
    close(fd2);
    if(epoll_events_ptr) 
        free(epoll_events_ptr);

    return ;

}

测试结果:

有一点值得注意的是,我在测试用例中当收到epoll事件的时候直接进行了读取操作,实际应用中这一步可能会阻塞,更好的做法是收到事件发送消息到相关的线程或者是消息队列中,由它们来进行业务处理,epoll只负责通知,这样能够提高处理速度。

代码可以在gihub上克隆:

git@github.com:FuYuanDe/epoll.git

参考资料:

http://www.man7.org/linux/man-pages/man7/epoll.7.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值