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;
}
	

  

原文地址:https://www.cnblogs.com/gd-luojialin/p/10371597.html