epoll----ET工作模式下实现多个客户机与服务机之间的通讯

(注:由于前面写过select和poll函数,在epoll函数中大部分代码会和钱前面两个的函数重复,所以在下面的代码中,不再注释
重复代码,只将与之不同的代码注释,读者可以通过“https://mp.csdn.net/postedit/83215953”或者“https://blog.csdn.net/xing1584114471/article/details/83343021”、“https://blog.csdn.net/xing1584114471/article/details/83451149”了解)

头文件以及宏定义:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>

#define MAXFD 10

子函数(给描述符设置非阻塞属性):

void setnonblock(int fd)
{
	int oldfl = fcntl(fd, F_GETFL);
	int newfl = oldfl | O_NONBLOCK;
	if(fcntl(fd, F_SETFL, newfl) == -1)
	{
		perror("fcntl error!\n");
	}
}

子函数(将描述符fd添加到事件表上):

void epoll_add(int epfd, int fd)
{
	struct epoll_event ev;
	ev.events = EPOLLIN | EPOLLEL;//事件多加一个EL工作模式
	ev.data.fd = fd;

	if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
	{
		perror("epoll_ctl add error!");
	}
	setnonblock(fd);//给fd添加上非阻塞属性
}

子函数(从事件表上讲描述符fd删除掉):

void epoll_del(int epfd, int fd)
{
	if(epoll_ctl(fd, EPOLL_CTL_DEL, fd, NULL) == -1)
	{
		perror("epoll_ctl del error!");
	}
}

实现函数:

int main()
{
	//前面代码和TL工作模式相同
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	assert(sockfd != -1);

	struct sockaddr_in saddr, caddr;
	memset(&saddr, 0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(6000);
	saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

	int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
	assert(res != -1);

	listen(sockfd, 5);

	int epfd = epoll_create(MAXFD);
	epoll_add(epfd, sockfd);
	struct epoll_event events[MAXFD];

	while(1)
	{
		int n = epoll_wait(epfd, events, MAXFD, 50000);
		if( n  == -1)
		{
			printf("epoll_wait error!\n");
			continue;
		}
		if( n == 0)
		{
			printf("time out!\n");
			continue;
		}
		else
		{
			int i = 0;
			 for( ; i < n; i++)
			 {
				 int fd = events[i].data.fd;
				 if(events[i].events & EPOLLIN)
				 {
					 if(fd == sockfd)
					 {
						 int len = sizeof(caddr);
						 int c = accept(fd, (struct sockaddr*)&caddr, &len);
						 if( c < 0 )
						 {
							 printf("accept error!\n");
							 continue;
						 }
						 printf("accept = %d\n",c);
						 epoll_add(epfd, c);
					 }
					 else
					 {
						 while(1)
						 {
							 char buff[128] = {0};
							 int num = recv(fd, buff, 127, 0);
							 if(num == -1)//当收到的num返回值为-1就代表该描述符上的数据被读完
							 {
								 if(errno == EAGIN | errno = EWOULDBLOCK)// EAGIN和EWOULDBLOCK两个errno值是该描述符上数值读完数据的返回值
								 {
									 send(fd, "ok", 2, 0);//判断是真的如果读完数据就给客户端发送"ok"
								 }	 
								 break;
							 }
							 else if( num == 0)//如果返回值为0就代表客户端断开了连接
							 {
								 printf("one over!\n");
								 epoll_del(epfd, fd);
								 close(fd);
								 break;
							 }
							 else
							 {
								 printf("recv(%d) buff = %s\n",fd, buff);
							 }
						 }
					 }
				 }
			 }
		}
	}
	exit(0);
}

猜你喜欢

转载自blog.csdn.net/xing1584114471/article/details/83451158