网络编程12——epoll实现多路转接思想及实现⭐

epoll实现多路IO转接思路

	lfd = socket();			
	bind();
	listen();
	//开始epoll监听
	int epfd = epoll_create(1024);      //监听红黑树的树根
	struct epoll_event tep, ep[1024];     // tep用来设置单个fd属性,ep是epoll_wait()传出的满足监听事件的数组
	tep. events = EPOLLIN;	//初始化lfd的监听属性,每个加到树上的fd都要初始化监听属性
	tep.data.fd = lfd 
	epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tep );//将lfd添加到监听红黑树上
	while(1)
	{
		ret = epoll_wait(epfd, ep, 1024, -1);		//实施监听,ret表示满足监听事件的总个数
		for(i = 0; i<ret; i++)//把满足的事件都加到了ep数组中,ret就是总个数,就是循环上限
		{	//要去判断这个事件是lfd还是cfd产生的
			if(ep[i].data.fd == lfd)//lfd满足读事件,有新的客户端发起连接请求
			{
				cfd = Accept();
				//要将新加的加入到红黑树中,首先初始化监听属性,把fd放到tep这个结构体中,放到数组中
				tep.events = EPOLLIN;
				tep.data.fd = cfd;				//初始化cfd的监听属性
				epoll_ctl(epfd, EPLOO_ADD, cfd, &tep);
			}else
			{
				//不是lfd,那就是cfd,那就处理cfd的读事件,有客户端写数据
				n = read(ep[i].data.fd, buf, sizeof(buf));
				if(n == 0)	//表示对端关闭
				{
					//要把这个节点从树上摘下来
					epoll_ctl(epfd, EPOLL_CTL_DEL,cfd, &tep,NULL);
					close(ep[i].data.fd);	//客户端关闭了,服务器端也可以关闭了
					
				}else if(n>0)//大于0表示已经read完了
				{
					toupper();
					write(ep[i].data.fd, buf, n);
				}
				
			}
		}
		
	}

在这里插入图片描述

epoll函数实现的多路IO转接

#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<errno.h>
#include<ctype.h>
#include<string.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

#define OPEN_MAX 5000

int main(int argc, int argv[])
{
	int i, listenfd, connfd, sockfd;
	int n,num = 0;
	ssize_t nready, edf, res;
	char buf[MAXLINE], str[INET_ADDRSTRLEN];
	socklen_t clilen;
	struct sockaddr_in servaddr, cliaddr;
	struct epoll_event tep, ep[OPEN_MAX];//tep是epoll_ctl的参数,ep[]是epoll_wait的参数
	//ep[]是结构体数组,放的是tep这样的一个个的小结构体
	//-------------------------------------------------------开始socket
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	int opt = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	Bind(listenfd, (struct sockaddr*)&servaddr,sizeof(servaddr));
	Listen(listenfd, 20);
	//-------------------------------------------epoll监听
	//创建epoll模型(红黑树根节点
	efd = epoll_create(OPEN_MAX);//OPEN_MAX是预估的节点数
	if(epd == -1)
		perr_exit("epoll_create error");
	//先处理lfd, 放到tep结构体中,再将结构体挂到树上
	tep.data.fd = listenfd;
	tep.events = EPOLLIN;
	res = epoll_ctl(efd, EPOLL_CTL_ADD, listefd, &tep)//结构体tep挂到以efd为根节点的树上
	if(res == -1)
		perr_exit("epoll_ctl error");
	//------------------------------------------有了树根和第一个lfd,开始阻塞监听
	while(1)
	{
		nready = epoll_wait(efd, ep, OPEN_MAX, -1);//ep是数组,-1表示永久阻塞,open_max为数组容量,返回的是满足监听事件的总个数⭐ep是不用自己去维护的!吗?
		if(nready == -1)
			perr_exit("epoll_wait error");
		for(i = 0; i<nready; i++)
		{
			if(!(ep[i].events & EPOLLIN))//如果不是读事件,就继续
				continue;
			if(ep[i].data.fd == listenfd)//判断满足事件的fd是不是lfd
			{//是,就给分配cfd
				clilen = sizeof(cliaddr);
				connfd = Accept(listenfd, (struct addr*)cliaddr, &clilen);
				printf("received from %s at port %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));//是网络给了一个专门函数,端口就还是用简单的
				printf("cfd %d -----client %d\n", connfd, ++num);
				//把cfd加到tep结构体中,再挂到树上
				tep.events = EPOLLIN;
				tep.data.fd = connfd;
				res = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &tep);
				if(res == -1)
					perr_exit("epoll_ctl error");
			}else//是cfd
			{
				sockfd = ep[i].data.fd;
				n = Read(sockfd, buf, MAXLINE);
				if(n == 0)//客户端关闭连接
				{
					res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);//从树上摘下
					if(res == -1)
						perr_exit("epoll_ctl error");
					Close(sockfd);
					printf("client[%d] closed connection \n",sockfd);
				}else if(n < 0)
				{
					perror("read < 0 error:");
					res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);
					Close(sockfd);
				}else//正常
				{
					for(i = 0; i < n; i++)
					{
						buf[i] = toupper(buf[i]);
					}
					Write(STDOUT_FILENO, buf, n);
					Write(sockfd, buf, n);
				}
				
			}
		}
	}
	Close(listenfd);
	Close(efd);
	return 0;
}

//所以那个ep数组是不用自己维护的==jin好

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值