Linux socket编程--epoll --实例

本文详细介绍了Linux内核中的epoll机制,作为select和poll的增强版,epoll在处理大量socket描述符时具有更高的效率。文章通过创建epoll实例、修改兴趣列表和等待事件三个步骤,展示了epoll的工作流程,并提供了一个服务器端的示例代码,演示了如何使用epoll监听和响应客户端连接及读写操作。
摘要由CSDN通过智能技术生成

epoll 是Linux 2.6内核提出的 ,可以理解其为select和poll的增强版
优点:
支持一个进程打开大数目的socket描述符(FD)
IO效率不随FD数目增加而线性下降
epoll还维护了一个双链表,用户存储发生的事件
一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题

实现epoll逻辑
1、创建epoll实例:epoll_create()
2、修改epoll的兴趣列表:epoll_ctl()
3、事件等待:epoll_wait()
实例

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

#define MAX_LISTEN_QUE	13
#define MAXEVENTSIZE 512
#define BUFF "hello client , i'm server!"
//初始化并返回套接字函数,socket、bind、listen
int socket_init(void)
{
	int ser_fd = -1;
	int rv = -1;
	int on = 1;
	int port = 9998;
	struct sockaddr_in ser_addr;

	ser_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(ser_fd < 0)
	{
		printf("create socket failure:%s\n", strerror(errno));
		return -1;
	}
	printf("\ncreate socket[%d]successfully!\n",ser_fd);

	if((rv = setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
	{
		printf("\n设置地址重用失败:%s\n",strerror(errno));
		return -1;
	}

	memset(&ser_addr, 0, sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(port);
	ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	rv = bind(ser_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
	if(rv < 0)
	{
		printf("ser_fd[%d]bind port[%d]failure:%s\n", ser_fd, port, strerror(errno));
		return -1;
	}
	printf("\nser_fd[%d]bind port[%d]successfully!\n", ser_fd, port);

	rv = listen(ser_fd, MAX_LISTEN_QUE);
	if(rv < 0)
	{
		printf("\nser_fd[%dlisten port[%d]failure:%s\n", ser_fd, port, strerror(errno));
		return -1;
	}
	printf("\nser_fd[%dlisten port[%d]successfully!\n", ser_fd, port);
	
	return ser_fd;
}


int main(int argc, char **argv)
{
	int listenfd = socket_init();
	int epollfd;
	int rv,num,connfd;
	struct epoll_event event;				
	struct epoll_event events_array[MAXEVENTSIZE];
	struct sockaddr_in cliaddr;
	char buff[1024] = {};
	socklen_t len;

	epollfd = epoll_create(111);//创建一个新的epoll实例(描述符),其对应的兴趣列表初始化为空。

	if((epollfd = epoll_create(111)) < 0)
	{
		printf("epoll_create failure:%s\n", strerror(errno));	
		return -1;
	}
	printf("epoll_create [%d] successfully!\n", epollfd);	
	
	event.events =  EPOLLIN;
	event.data.fd = listenfd;
	rv = epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd,  &event);
	if(rv < 0)
	{
		printf("epoll_trl failure:%s\n", strerror(errno));
		close(epollfd);
		return -1;
	}
	while(1)	
	{
		printf("epoll waiting····\n");
		num = epoll_wait(epollfd, events_array, MAXEVENTSIZE, -1);
		if(num < 0)
		{
			printf("epoll_wait failure:%s\n", strerror(errno));
			close(epollfd);
			return -1;
		}
		else if(num ==0)
		{
			printf("eopll_wait timeout!\n");
			close(epollfd);
			continue;
		}
		printf("epoll_wait successfully and return %d \n", num);
		
		for(int i=0; i<num; i++)
		{
			if(events_array[i].events == EPOLLIN && events_array[i].data.fd == listenfd)
			{
				connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
				if(connfd < 0)
				{
					printf("accpet new client failure:%s\n", strerror(errno));
					continue;
				}
				printf("accpet new client[%d] successfully\n", connfd);
				//将新连接进来的客户端注册到epollfd中
				event.events = EPOLLIN;
				event.data.fd = connfd;
				rv = epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event);
				if(rv == 0)
				{
					printf("add new connfd[%d] to epollfd successfully!\n", connfd);
				}
				else if(rv < 0)
				{
					printf("add new connfd[%d] to epollfd failure:%s\n", connfd, strerror(errno));
					close(connfd);
					continue;
				}
			}
			else
			{	
				memset(buff, 0, sizeof(buff));
				rv = read(events_array[i].data.fd, buff, sizeof(buff));
				if(rv < 0)
				{
					printf("read data from client[%d]failure:%s\n", events_array[i].data.fd, strerror(errno));
					close(events_array[i].data.fd);
					continue;
				}
				else if(rv == 0)
				{
					printf("client[%d] get disconnetion!\n", events_array[i].data.fd);
					close(events_array[i].data.fd);
					continue;
				}
				printf("read data from client[%d]successfully:%s\n", events_array[i].data.fd, buff);
				 
				rv = write(events_array[i].data.fd, BUFF, strlen(BUFF));
				if(rv < 0)
				{
					printf("send data to client[%d]failure:%s\n", events_array[i].data.fd, strerror(errno));
					close(events_array[i].data.fd);
					continue;
				}
				printf("send data to client[%d]successfully\n", events_array[i].data.fd);
			}
			
		}
	}
	close(listenfd);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值