linux epoll监听套接字实例
程序员文章站
2022-05-18 14:48:57
...
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 : aaa@qq.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上克隆:
aaa@qq.com:FuYuanDe/epoll.git
参考资料:
http://www.man7.org/linux/man-pages/man7/epoll.7.html
上一篇: SetThreadAffinityMask中掩码的问题
下一篇: php 实现 select系统调用
推荐阅读
-
Linux进程间通信——使用流套接字
-
Linux下重启oracle服务及监听器和实例详解
-
一起talk C栗子吧(第一百六十二回:C语言实例--套接字知识体系图)
-
一起talk C栗子吧(第一百六十回:C语言实例--套接字通信模型二)
-
《Linux网络编程》: 原始套接字发送UDP报文
-
linux网络编程高级篇-原始套接字【简单的抓包实现】
-
一起talk C栗子吧(第一百五十八回:C语言实例--基于AF_INET域的流套接字通信)
-
一起talk C栗子吧(第一百六十回:C语言实例--套接字通信模型一)
-
linux下重启oracle服务:监听器和实例
-
linux进程间通信---本地socket套接字(五)---多路IO转接服务器实现一个server对应多个client---poll实现