⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 epoll_t.cc

📁 介绍epoll
💻 CC
字号:
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#define INFTIM 1000

void setnonblocking(int sock)
{
	int opts;
	opts = fcntl(sock, F_GETFL);
	if (opts < 0)
	{
		perror("fcntl(sock, GETFL)");
		exit(1);
	}
	opts = opts|O_NONBLOCK;
	if (fcntl(sock, F_SETFL, opts) < 0)
	{
		perror("fcntl(sock, SETFL, opts)");
		exit(1);
	}
}

// 发送数据
ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)
{
	ssize_t tmp;
	size_t total = buflen;
	const char *p = buffer;

	while(1)
	{
		tmp = send(sockfd, p, total, 0);
		if(tmp < 0)
		{
			// 当send收到信号时,可以继续写,但这里返回-1.
			if(errno == EINTR)
			{
				return -1;
			}

			// 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,
			// 在这里做延时后再重试.
			if(errno == EAGAIN)
			{
				usleep(1000);
				continue;
			}

			return -1;
		}

		if((size_t)tmp == total)
		{
			return buflen;
		}

		total -= tmp;
		p += tmp;
	}

	return tmp;
}

int main()
{
	int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
	ssize_t rs, n = 0;
	char line[MAXLINE];
	int l_sinSize = 0;
	l_sinSize = sizeof(struct sockaddr);

	// 声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
	struct epoll_event ev, events[20];
	// 生成用于处理accept的epoll专用的文件描述符
	epfd = epoll_create(256);

	struct sockaddr_in clientaddr;
	struct sockaddr_in serveraddr;
	listenfd = socket(AF_INET, SOCK_STREAM, 0);

	// 把socket设置为非阻塞方式
	setnonblocking(listenfd);

	// 设置与要处理的事件相关的文件描述符
	ev.data.fd = listenfd;
	// 设置要处理的事件类型
	ev.events = EPOLLIN|EPOLLET;
	// 注册epoll事件
	epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);


	bzero(&serveraddr, sizeof(struct sockaddr_in));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serveraddr.sin_port = htons(SERV_PORT);
	bind(listenfd, (struct sockaddr *)(&serveraddr), sizeof(struct sockaddr));
	listen(listenfd, LISTENQ);
	maxi = 0;
	for ( ; ; ) 
	{
		// 等待epoll事件的发生
		nfds=epoll_wait(epfd,events,20,500);
		// 处理所发生的所有事件
		for (i = 0; i < nfds; ++i)
		{
			if (events[i].data.fd == listenfd)
			{
				connfd = accept(listenfd, (struct sockaddr *)(&clientaddr), (socklen_t *)&l_sinSize);
				if (connfd < 0)
				{
					perror("connfd < 0");
					exit(1);
				}
				setnonblocking(connfd);
				char* str = inet_ntoa(clientaddr.sin_addr);
				std::cout<<"connect from "<<str<<std::endl;
				// 设置用于读操作的文件描述符
				ev.data.fd = connfd;
				// 设置用于注测的读操作事件
				ev.events = EPOLLIN|EPOLLET;
				// 注册ev
				epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
			}
			else if (events[i].events&EPOLLIN)
			{
				if ((sockfd = events[i].data.fd) < 0)
				{
					continue;
				}
/*
				if ((n = read(sockfd, line, MAXLINE)) < 0)
				{
					if (errno == ECONNRESET)
					{
						close(sockfd);
						events[i].data.fd = -1;
					}
					else
					{
						std::cout<<"readline error"<<std::endl;
					}
				}
				else if (n == 0)
				{
					close(sockfd);
					events[i].data.fd = -1;
				}

*/				
				while(rs)
				{
					n = recv(sockfd, line, MAXLINE, 0);
					if(n < 0)
					{
						// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读
						// 在这里就当作是该次事件已处理处.
						if(errno == EAGAIN)
						{
							break;
						}
						else
						{
							return;
						}
					}
					else if(n == 0)
					{
						// 这里表示对端的socket已正常关闭.
					}

					if(n == sizeof(line))
					{
						rs = 1;   // 未读完 需要再次读取
					}
					else
					{
						rs = 0;
					}
				}

				//设置用于写操作的文件描述符
				ev.data.fd = sockfd;
				//设置用于注测的写操作事件
				ev.events = EPOLLOUT|EPOLLET;
				//修改sockfd上要处理的事件为EPOLLOUT
				epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
			}
			else if(events[i].events&EPOLLOUT)
			{
				sockfd = events[i].data.fd;
				ssize_t l_writeSize = write(sockfd, line, n);
				std::cout<<"write "<<l_writeSize<<std::endl;
				//设置用于读操作的文件描述符
				ev.data.fd = sockfd;
				//设置用于注测的读操作事件
				ev.events = EPOLLIN|EPOLLET;
				//修改sockfd上要处理的事件为EPOLIN
				epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
			}
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -