linux下I/O复用与epoll实际使用(三)

前两章已经学习了epoll根据前两篇的学习,基本掌握了epoll事件,但对于同时监控读写事件还未涉及到,故作一次补充
server端

#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include<stdbool.h>

int gSetNonblocking(int fd)
{
	int old_option=fcntl(fd,F_GETFL);
	int new_option=old_option|O_NONBLOCK;
	fcntl(fd,F_SETFL,new_option);
	return new_option;
}


typedef struct fd_info_s
{
	int fd;
	int type;/*-1,非法 0:server 1:client*/
}fd_info_t;
//数组大小可根据需要扩充
fd_info_t g_fds[512];


int main(int argc,char *argv[])
{
	struct sockaddr_in addr;
	int epollfd;
	struct epoll_event event1;
	int fd;
	int ret;
	/*创建epollfd*/
	epollfd=epoll_create(20);
	
	/*添加第一个fd,用于accept*/
	fd=socket(AF_INET,SOCK_STREAM,0);
	if(fd<0)
	{
		dprintf(STDERR_FILENO,"socket error",14);
		return -1;
	}	
	
	//先要对协议地址进行清零
	bzero(&addr,sizeof(addr));
	//设置Ipv4或ipv6
	addr.sin_family=AF_INET;
	//绑定本地端口号
	addr.sin_port=htons(atoi(argv[1]));
	//任何一个 IP 地址,让内核自行选择
	addr.sin_addr.s_addr=INADDR_ANY;
	//绑定套接口到本地协议地址
	bind(fd,(struct sockaddr *)&addr,sizeof(addr));
	//服务器开始监听
	listen(fd,32767);
	gSetNonblocking(fd);
	
	
	//填充fd对应的结构体
	g_fds[fd].fd=fd;
	g_fds[fd].type=0;
	
	event1.data.ptr=&g_fds[fd];
	event1.events=EPOLLIN|EPOLLRDHUP;	
	ret=epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event1);
	if(ret!=0)
	{
		if(errno==EEXIST)
		{
			epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event1);
		}		
	}	
	//printf("epollctl1\n");
	while(1)
	{
		int number;
		int i;
		struct epoll_event ep_events[512];
		fd_info_t *pfdinfo;
		
		//监听最大512个事件
		number=epoll_wait(epollfd,ep_events,512,-1);
		if(number < 0 && errno !=EINTR)
		{
			printf("epoll failure\n");
			break;
		}
		//printf("num=%d\n",number);
		for(i=0;i<number;i++)
		{
			
			pfdinfo=ep_events[i].data.ptr;			
			if(pfdinfo->type == 0 && (ep_events[i].events & EPOLLIN))
			{
				struct sockaddr_in cliaddr;
				socklen_t clilen =sizeof(struct sockaddr_in);
				fd=accept(pfdinfo->fd,(struct sockaddr *)&cliaddr,&clilen);
				printf("\n accept fd: %d\n",fd);
				
				g_fds[fd].fd=fd;
				g_fds[fd].type=1;
				event1.data.ptr=&g_fds[fd];
				event1.events=EPOLLIN|EPOLLRDHUP;	
				ret=epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event1);
				if(ret!=0)
				{
					//如果事件已经添加过,则更改其状态
					if(errno==EEXIST)
					{
						epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event1);
					}					
				}			
			}
			
			if(pfdinfo->type == 1 && (ep_events[i].events & EPOLLIN))
			{
				char text[512];
				int ret=recv(pfdinfo->fd,text,512,0);
				if(ret>0)
				{
					text[ret]='\0';
					//printf("Recv(%d):%s\n",ret,text);
					printf("request fd:%d\n",pfdinfo->fd);
					g_fds[pfdinfo->fd].fd=pfdinfo->fd;
					g_fds[pfdinfo->fd].type=1;
					event1.data.ptr=&g_fds[pfdinfo->fd];
					event1.events=EPOLLIN|EPOLLRDHUP|EPOLLOUT;;	
					ret=epoll_ctl(epollfd,EPOLL_CTL_MOD,pfdinfo->fd,&event1);				
				}
				else if(ret==0)
				{
					event1.events=0;
					//删除事件
					ret=epoll_ctl(epollfd,EPOLL_CTL_MOD,pfdinfo->fd,&event1);
					printf("ret=%d\n",ret);
					perror("");
					close(pfdinfo->fd);
					printf("\n close fd: %d\n",pfdinfo->fd);
					g_fds[pfdinfo->fd].fd=-1;
					break;
				}
				else if(errno == EWOULDBLOCK)
				{
					printf("wouldblock\n");
					break;
				}
				else if(errno == EPIPE)
				{					
					printf("Broken pipe\n");
					break;
				}				
			}
			
			if(pfdinfo->type == 1 && (ep_events[i].events & EPOLLOUT))
			{
				int n;	
				char text[512];				
				sprintf(text,"%s","this is epoll server say hello\n");
				n=strlen(text);
				write(pfdinfo->fd,text,n);
				printf("reply fd:%d\n",pfdinfo->fd);
				event1.events=EPOLLIN|EPOLLRDHUP;	
				ret=epoll_ctl(epollfd,EPOLL_CTL_MOD,pfdinfo->fd,&event1);				
			}
		}			
	}
	
}

client端:

#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/un.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/epoll.h>
#include <fcntl.h>
 
#define path "tempfile.socket"

int sock;
int epollfd;
void sig(int sig)
{
	char buf[512];
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "close client %d",sock);
	
	write(sock, buf, strlen(buf));
	close(epollfd);
	close(sock);		
}
 void gCtrlfd(int epollfd,int fd,struct epoll_event event)
{
	int ret;
	ret=epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
	if(ret!=0)
	{
		if(errno==EEXIST)
		{
			epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event);
		}
	}
	
}

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		printf("Usage:./exec [port]\n");
		exit(-1);
	}
	signal(SIGINT, sig);
	sock = socket(AF_INET, SOCK_STREAM, 0);
 
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(argv[1]));
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 
	connect(sock, (struct sockaddr *)&addr, sizeof(addr));
 
	int old = fcntl(sock, F_GETFL);
	int newoption = old | O_NONBLOCK;
	fcntl(sock, F_SETFL, newoption);
 
	char buf[512];
	memset(buf, 0, sizeof(buf));
	/*创建epoll fd*/
	epollfd = epoll_create(5);
 
	struct epoll_event event[128]; 
	struct epoll_event e1,e2,e3;
	
	/*将e1 e2 初始化*/
	
	e1.data.fd = sock;
	e1.events = EPOLLIN;
	gCtrlfd(epollfd,sock,e1); 
	e2.data.fd = STDIN_FILENO;
	e2.events = EPOLLIN;
	gCtrlfd(epollfd,STDIN_FILENO,e2); 
	
	int nR;
	int ret;
	int i;
	while (1)
	{
		
		int number = epoll_wait(epollfd, event, 128, -1);
		if (number <= 0)
		{
			printf("epoll_wait error\n");
			return 0;
		}
	//	printf("num=%d\n",number);
		for(i = 0; i < number; ++i)
		{
 
			if (event[i].data.fd == sock)
			{
				if(event[i].events & EPOLLIN)
				{
					if(event[i].data.fd == sock)
					{
						memset(buf, 0, sizeof(buf));
						nR = read(sock, buf, 512);
						if (nR == 0)
						{
							close(sock);
							break;
						}
						printf("%s\n",buf);
						e1.data.fd = sock;
						e1.events = e1.events | EPOLLOUT;
						gCtrlfd(epollfd,sock,e1);
					}
				}
				if(event[i].events & EPOLLOUT)
				{
					memset(buf, 0, sizeof(buf));
					printf("aaaa\n");
					sprintf(buf,"%s","this is client: say hello\n");
					nR=sizeof(buf);
					write(sock, buf, nR);
					e1.data.fd = sock;
					e1.events = e1.events& ~EPOLLOUT;
					gCtrlfd(epollfd,sock,e1);
				}
			}
			else if ( event[i].data.fd == STDIN_FILENO && (event[i].events & EPOLLIN))
			{
				printf("please input string:");
				fflush(stdout);
				memset(buf, 0, sizeof(buf));
				nR = read(STDIN_FILENO, buf, 512);
				if (nR <= 0)
				{
					printf("errno[%d]:%s\n", errno, strerror(errno));
				}
			
				ret = write(sock, buf, nR);
				if (ret == 0 && errno == EINTR)
				{
					printf("write sock error\n");
					exit(-1);
				}
				else if (ret < 0)
				{
					printf("write sock ret < 0\n");
					exit(-1);
				}
				printf("Send [%d]byte\n", ret);
			}
		}
	}
 
	close(sock);
 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值