• 多路IO复用--epoll


    api
    • epoll_create(int size); // 创建epoll
    • epoll_ctl(int epfd,EPOLL_OP,sockfd,event); // 设置epoll, EPOLL_OP, 为epll操作事件,对应的fd
    • epoll_wait(epfd,events,length,0); // 将就绪队列从内核态到用户态

    在内核中创建epoll,accept创建io,判断是否加入到内核中,每一次将就绪的io切换到用户态

    触发方式

    水平触发(LT) :满足IO复用条件即触发
    边沿触发 (ET) : 新的IO就绪事件到达即触发

    如客户端一次发送数据100个字节数据到服务端,服务端一次读50个字节,
    服务器设置为水平触发,则recv执行2次,
    服务器设置为边缘触发,则recv执行1次

    使用场景: 对于发送的数据包较大,则设置为边缘触发触发,循环读取数据;数据包较小,则设置为水平触发

    service-epoll:

    运行服务端程序,将阻塞在epoll_wait,当客户端连接时,服务端接收客户端buffer,并发送buffer给客户端

    	int sockfd= socket(AF_iNET,SOCK_STREAM,0);
    	if(sockfd == -1) {
    		return -1;
    	}
    	struct socketaddr_in servaddr;
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    	servaddr.sin_port = htons(9999);
    
    	if(-1 = bind(sockfd,(struct sockaddr*)&servaddr),sizeof(servaddr)){
    		return -2;
    	}
    	//nonblock
    	int flag = fcntl(sockfd,F_GETFL,0);
    	flag |= O_NONBLOCK;
    	fcntl(sockfd,F_SETFL,flag);
    	
    	listen(sockfd,10);
    	
    	//epoll
    	int epfd = epoll_create(1);
    	struct epoll_event ev;
    	ev.events = EPOLLIN;
    	ev.data.fd = sockfd;  // 8个字节
    	epoll_ctl(epfd,EPOLL_CEL_ADD,sockfd,&ev); 
    	
    	struct epoll_event events[1024] = {0}; // events快递员装快递的袋子
    	
    	struct sockaddr_in clientaddr;
    	socklen_t len = sizeof(client);
    	while(1) {  // loop
    	 	int nready = epoll_wait(epfd,events,1024,-1);// 判读IO有没有就绪事件,快递员多长时间取快递  最后一个参数,-1 一直等待,0,不等待,1,等待一段时间
    	 	if(nready < 0 ) continue;
    	 	int i = 0;
    	 	// set 链接额的客户端 ready 盒子
    	 	for(i = 0; i< nready;i++) {
    	 		int connfd = events[i].data.fd;
    	 		if(sockfd == connfd) {
    	 			int clientfd = accept(sockfd,(struct sockaddr *)clientaddr,&len);
    	 			if(clientfd <= 0 ) {
    	 				continue;
    	 			}
    	 			printf("clientfd = %d",clientfd);
    	 			// EPOLLET 边沿触发
    	 			ev.events = EPOLLIN | EPOLLET;
    	 			ev.data.fd = clientfd;
    	 			epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&ev); 
    	 		}
    	 		else if (events[i].events & EPOLLIN) {
    	 			char buffer[BUFFER_LENGTH] = {0};
    	 			int n = recv(connfd,buffer,BUFFER_LENGTH);
    	 			if(n > 0) {
    	 				// 服务器先接受客户端的buffer,再将buffer发送给客户端
    	 				printf("recv : %s\n",buffer);
    	 				send(connfd,buffer,n,0);
    	 			} else if (n == 0) {
    	 				printf("close\n");
    	 				// 用户搬走
    	 				epoll_ctl(epfd,EPOLL_CTL_DEL,connfd,NULL);
    	 				// 如不移除,connfd的值将会一直存在
    	 				close(connfd);
    	 			}
    	 		}
    	 	}
    	 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    java-net-php-python-ssm巴音学院餐饮安全与卫生防御管理系统计算机毕业设计程序
    USART串口协议
    Python3操作redis百万级数据迁移,单机到单机,集群到集群
    弘辽科技:淘宝免费流量扶持怎么用?新店流量扶持规则是啥?
    实验四:健康打卡
    【Linux】《Linux命令行与shell脚本编程大全 (第4版) 》笔记-Chapter24-编写简单的脚本实用工具
    vue2时间处理插件——dayjs
    基于Web的大众汽车租赁系统设计与实现-计算机毕业设计源码+LW文档
    如何记录每天的工作日程?电脑手机通用的日程管理软件
    微信公众号根据URL取文章详情 API 返回值说明
  • 原文地址:https://blog.csdn.net/qq_43538607/article/details/138194033