zoukankan      html  css  js  c++  java
  • 33网络通信之Epoll模型

     多路复用并发模型  -- epoll

    监控事件 events

    EPOLLIN                  fd可读

    EPOLLOUT              fd可写

    EPOLLPRI                fd紧急数据可读

    EPOLLERR              fd发生错误

    EPOLLHUP              fd 被挂起

    EPOLLONESHOT    fd 只监控 1 次,监控完后自动删除

    EPOLLLT                 epoll 工作模式,设置为 水平触发模式

    EPOLLET                 epoll 工作模式,设置为 边缘触发模式

    多路复用并发模型  -- epoll

    epoll 工作模式

    1)水平触发模式 (Level Triggered, 默认值)

      事件发生时,应用程序可以不立即处理。

      没有做处理,则下次epoll_wait 事件仍然被置位

    2)边缘触发模式 (Edge Triggered)

      事件发生时,应用程序必须处理

      否则,这个事件会被丢弃

    epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死

    水平触发模式和边缘触发模式

      水平触发监控的是状态:   有没有消息可读

      边缘触发监控的是变换: 是不是由可读变成不可读,或者由不可读变成可读

     

    #include<stdio.h>
    #include<unistd.h>
    #include<string.h>
    
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    
    #include <map>
    
    #include<sys/epoll.h>
    #include<sys/time.h>
    
    #define SRV_PORT 0xabcd
    #define DEAL_NUM 2
    #define  CONN_MAX 10000
    
    int fd;
    int nConn = 0;//num of connection
    std::map<int, struct socket_in> g_fdmap;
    
    void epoll_process(int epfd,struct epoll_events,int cnt)
    {
    	int i, iRet = 0;;
    	int newfd;
    	char szBuff[1000];
    	struct sockaddr_in addr;
    	socklen_t addrlen = sizeof(addr);
    	struct epoll_event ect;
    
    	std::map<int struct socket_in>::iterator  it;
    
    	for (i = 0; i < cnt; ++i)
    	{
    		//Accept the message and process it
    		if (evts[i].data.fd == STDIN_FILENO)
    		{
    
    		}
    		//new client to connet
    		else if (evts[i].data.fd == fd)
    		{
    			newfd = accept(fd, (struct sockaddr*)&addr, &addrlen);
    			if (newfd < 0)
    			{
    				perror("Fail to accept!");
    				continue;;
    			}		
    			if (nConn == CONN_MAX)
    			{
    				write(newfd, "Over limit!", 12);
    				printf("Over connect..
    ");
    				close(newfd);
    				continue;
    			}
    			//normal operation
    			g_fdmap.insert(std::make_pair(newfd, addr));
    			
    			//add newfd to epfd for monitor
    			evt.events = EPOLLIN;
    			evt.data.fd = newfd;
    			epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &evt);
    
    			//reponse client
    			write(newfd, "Welcome", 8);
    
    			printf("
    New Connect from %s[%d]
    ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    
    		}
    		//recviver client message
    		else
    		{
    			memset(szBuff, 0, 1000);
    			
    			it = g_fdmap.find(evts[i].data.fd);
    			if (it == g_fdmap.end())
    			{
    				printf("
    Unknow client fd: %d
    ", evts[i].data.fd);
    				continue;
    			}
    
    			iRet=read(evts.data.fd, szBuff, 1000);
    			if (iRet < 0)
    			{
    				perror("Fail to read!");
    				continue;
    			}
    			else if (iRet == 0)
    			{
    				printf("Disconnct from %s[%d]
    ", inet_ntoa((it->second()).sin_addr), 
    					ntohs((it->second()).addr.sin_port));
    
    				//delete fd from epfd monitor
    				epoll_ctl(epfd, EPOLL_CTL_DEL,evts[i].data.fd,evts+i);
    
    				//erase fa from map
    				g_fdmap.erase(it);
    			}
    			//normal operation
    			else
    			{
    				printf("
    Recv from %s[%d]:%s
    ", inet_ntoa((it->second()).sin_addr,
    					ntohs((it->second()).addr.sin_port), szBuff);
    			}
    			
    		}
    	}
    
    	return;
    }
    
    void StarEpoll()
    {
    	int iRet;
    	struct sockaddr_in addr;
    	socklen_t addrlen = sizeof(addr);
    
    	fd = socket(PF_INET, SOCK_STREAM, 0);
    	if (fd < 0)
    	{
    		perror("Fail to socket!");
    		return;
    	}
    
    	addr.sin_family = AF_INET;
    	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    	addr.sin_port = htons(SRV_PORT);
    
    	iRet = bind(fd, (struct sockaddr*)&addr, addrlen);
    	if (iRet)
    	{
    		perror("Fail to bind!");
    		close(fd);
    		return;
    	}
    
    	iRet = listen(fd, 100);
    	if (iRet)
    	{
    		perror("Fail to listen!");
    		close(fd);
    		return;
    	}
    
    	///////////////init epollfd
    	
    	int epfd = epoll_create(1);
    	if (epfd < 0)
    	{
    		perror("Fail to epoll_create!");
    		close(fd);
    		return;
    	}
    
    	struct epoll_event evt;
    
    	//add stdin
    	evt.events = EPOLLIN;
    	evt.data.fd =STDIN_FILENO;
    	epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO);
    
    	//add tcp server fd
    	evt.events = EPOLLIN;
    	evt.data.fd = fd;
    	epoll_ctl(epfd, EPOLL_CTL_ADD, &evt);
    
    	///////////////////////
    
    	struct epoll_event evts[DEAL_NUM];
    
    	int cnt;
    	while (1)
    	{
    		cnt = epoll_wait(epfd, evts, DEAL_NUM, -1);
    		if (cnt < 0)
    		{
    			perror("Fail to epoll_wait!");
    			break;
    		}
    		else if (cnt == 0)
    		{
    			//timeout
    			continue;
    		}
    		else
    		{
    			epoll_process(epfd, evts, cnt);
    		}
    	}
    
    	close(fd);
    	return;
    }
    
    int main()
    {
    	StarEpoll();
    	
    	return 0;
    }
    	
    

      

  • 相关阅读:
    Linux下Rootkit的另类检测
    用iptables抗御SYN Flood攻击
    用iptables抗御SYN Flood攻击
    突破极限 解决大硬盘上安装Sco Unix新思路
    突破极限 解决大硬盘上安装Sco Unix新思路
    安装、配置Vmware Esx Server 3.5视频全过程
    安装、配置Vmware Esx Server 3.5视频全过程
    应该如何对企业局域网性能传输进行测试分析
    Leetcode-944 Delete Columns to Make Sorted(删除列以使之有序)
    Leetcode-941 Valid Mountain Array(有效的山脉数组)
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/10371597.html
Copyright © 2011-2022 走看看