Epoll使用示例

#include "xdjaapi.h"
#include "log.h"
#include "utils.h"

#define SERVER_IP "0.0.0.0"
#define SERVER_PORT 1988
#define LISTEN_BACKLOG 5
#define MAX_FDS 256
#define TIMEOUT 3000

static volatile sig_atomic_t isterm = 0;   // 结束信号
static volatile sig_atomic_t isalarm = 0;  // 时钟信号(1秒1次)

static void sig_handler(int sig, siginfo_t *si, void *context)
{
    static siginfo_t empty_siginfo;
    if(!si) si = &empty_siginfo;
    switch(sig)
    {
        case SIGINT: case SIGTERM:
            isterm = sig;
            break;
		case SIGPIPE:
			break;
        case SIGALRM: 
            isalarm = sig;
            break;
        default:
            break;
    }
}

static void signals_register()
{
    struct sigaction act;
    struct itimerval interval;

    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = sig_handler;

    interval.it_interval.tv_sec = 1;
    interval.it_interval.tv_usec = 0;
    interval.it_value.tv_sec = 1;
    interval.it_value.tv_usec = 0;

    sigaction(SIGINT, &act, NULL);
    sigaction(SIGTERM, &act, NULL);
	sigaction(SIGPIPE, &act, NULL);
    sigaction(SIGALRM, &act, NULL);
    setitimer(ITIMER_REAL, &interval, NULL);
}

int main(int argc, char *argv[])
{
	int ret = 0;
	int server_fd = -1;

	int epfd = -1, nfds = 0, loop = 0;
	struct epoll_event event;
	struct epoll_event *pevents = NULL;

	int client_fd = -1;
	unsigned short client_port = 0;
	char client_ip[32+1] = {0};

	char buf_recv[2048+1] = {0};
	char buf_send[2048+1] = {"i hear you!"};

    log_open(basename(argv[0]), 1);
    
	server_fd = tcp_socket();
	if(server_fd == -1)
	{
		log_error("create server socket fd failed: %s", strerror(errno));
		return -1;
	}

	ret = tcp_bind(server_fd, SERVER_IP, SERVER_PORT);
	if(ret == -1)
	{
		log_error("bind server socket fd failed: %s", strerror(errno));
		goto EndP;
	}

	ret = tcp_listen(server_fd, LISTEN_BACKLOG);
	if(ret == -1)
	{
		log_error("listen server socket fd failed: %s", strerror(errno));
		goto EndP;
	}

	epfd = epoll_create(MAX_FDS);
	if(epfd == -1)
	{
		log_error("\"epoll_create\": %s", strerror(errno));
		goto EndP;
	}

	event.data.fd = server_fd;
	event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
	ret = epoll_ctl(epfd, EPOLL_CTL_ADD, server_fd, &event);
	if(ret == -1)
	{
		log_error("\"epoll_ctl\": %s", strerror(errno));
		goto EndP;	
	}

	pevents = (struct epoll_event*)malloc(MAX_FDS*sizeof(struct epoll_event));
	if(pevents == NULL)
		goto EndP;
	memset(pevents, 0, MAX_FDS*sizeof(struct epoll_event));

	signals_register();
	while(true)	
	{
        if(likely(isalarm))
		{
			log_info("alarm signal: %d", isalarm);
			isalarm = 0;
		}
		
        if(unlikely(isterm))
        {
            log_info("terminate signal: %d", isterm);
			isterm = 0;
            break;
        }

	    log_info("\"epoll_wait\" ...");
		nfds = epoll_wait(epfd, pevents, MAX_FDS, TIMEOUT);
		for(loop = 0; loop < nfds; loop++)
		{
			if(pevents[loop].data.fd == server_fd)
			{
				client_fd = tcp_accept(server_fd, client_ip, 32+1, &client_port);
				if(client_fd == -1)
				{
					log_error("client connect to server failed: %s", strerror(errno));
					continue;
				}
				log_info("client connect to server succeed %s: %d", client_ip, client_port);

				event.data.fd = client_fd;
				event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
				ret = epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &event);
				if(ret == -1)
				{
					log_error("\"epoll_ctl\": %s", strerror(errno));
					tcp_close(client_fd);
					continue;
				}
			}
			else if(pevents[loop].events & EPOLLIN)
			{
				log_info("readable ...");
				ret = tcp_recv(pevents[loop].data.fd, buf_recv, 2048+1);
				if(ret == 0)
				{
					log_info("server recv \"RST\" from client succeed: %d", pevents[loop].data.fd);
					epoll_ctl(epfd, EPOLL_CTL_DEL, pevents[loop].data.fd, NULL);
					tcp_close(pevents[loop].data.fd);
					continue;
				}
				else if(ret == -1)
				{
					log_error("server recv data from client failed: %s", strerror(errno));
					continue;
				}
				log_info("server recv data from client succeed %d: %s", ret, buf_recv);

				event.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
				event.data.fd = pevents[loop].data.fd;
				ret = epoll_ctl(epfd, EPOLL_CTL_MOD, pevents[loop].data.fd, &event);
				if(ret == -1)
				{
					log_error("\"epoll_epoll_ctl\": %s", strerror(errno));
					tcp_close(pevents[loop].data.fd);
					continue;
				}
			}
			else if(pevents[loop].events & EPOLLOUT)
			{
				log_info("writable ...");
				ret = tcp_send(pevents[loop].data.fd, buf_send, strlen(buf_send));
				if(ret == -1)
				{
					log_error("server send to client data failed: %s", strerror(errno));
					continue;
				}
				log_info("server send to client data succeed %d: %s", ret, buf_send);

				event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
				event.data.fd = pevents[loop].data.fd;
				ret = epoll_ctl(epfd, EPOLL_CTL_MOD, pevents[loop].data.fd, &event);
				if(ret == -1)
				{
					log_error("\"epoll_epoll_ctl\": %s", strerror(errno));
					tcp_close(pevents[loop].data.fd);
					continue;
				}
			}
			else if(pevents[loop].events & EPOLLERR || pevents[loop].events & EPOLLHUP)
			{
				epoll_ctl(epfd, EPOLL_CTL_DEL, pevents[loop].data.fd, NULL);
				tcp_close(pevents[loop].data.fd);
				continue;
			}
		}
	}

EndP:
	if(epfd >= 0) close(epfd);
	if(pevents != NULL) free(pevents);
	if(server_fd >= 0) tcp_close(server_fd);
	log_close();
	return 0;
}

### epoll 函数使用示例 #### 创建 epoll 实例 创建一个 epoll 实例,通常通过 `epoll_create1` 来完成。此函数返回一个新的 epoll 文件描述符。 ```c int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } ``` 这段代码初始化了一个新的 epoll 实例,并检查是否成功创建[^1]。 #### 定义事件结构体 定义要监控的事件类型以及关联的数据: ```c struct epoll_event event; event.events = EPOLLIN | EPOLLET; // 设置为边缘触发模式 event.data.fd = listen_sock; // 将监听套接字添加到 epoll 实例中 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &event) == -1) { perror("epoll_ctl: add listen socket to epoll instance failed"); close(epoll_fd); exit(EXIT_FAILURE); } ``` 这里配置了监听套接字上的读取就绪事件,并将其加入到了 epoll 实例里[^2]。 #### 处理事件循环 进入无限循环等待事件发生并处理这些事件: ```c while (true) { struct epoll_event events[MAX_EVENTS]; int n_fds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (n_fds == -1) { perror("epoll_wait"); break; } for (int i = 0; i < n_fds; ++i) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP)) { fprintf(stderr, "epoll error\n"); close(events[i].data.fd); continue; } else if (events[i].events & EPOLLIN) { handle_events(&events[i]); } } } close(epoll_fd); ``` 上述代码展示了如何利用 `epoll_wait` 阻塞直到有感兴趣的事件发生,之后遍历所有发生的事件并对它们做出响应[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值