epoll编程模型

服务器端程序:

/********************************************************************
	epoll_creat 创建一个epoll对象(内核中搞了个文件系统用来处理事件),
	一般epollfd = epoll_create()
 
	int epoll_create(int size);
 
	epoll_ctl(epoll_add/epoll_del的合体)往epoll对象中增加/删除某一个流的某一个事件
	
	//epfd	epoll句柄 	
	//fd 套接字
	//event
	//op 增加 切换模式(水平触发和边沿触发(只支持no-block socket)模式)删除
	//EPOLL_CTL_ADD
	//EPOLL_CTL_MOD
	//EPOLL_CTL_DEL
	
	epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
	
	//
	typedef union epoll_data
	{
		void		*ptr;
		int		 	  fd;
		_uint32_t	 u32;
		_uint64_t	 u64;
	}epoll_data_t;
 
	struct epoll_event
	{
		_uint32_t	 events;  //Epoll events
	    epoll_data_t data;   //User data variable
	}
	
	_uint32_t events :
	
			  The events member is a bit mask composed using the following available event types:

       EPOLLIN
              The associated file is available for read(2) operations.

       EPOLLOUT
              The associated file is available for write(2) operations.

       EPOLLRDHUP (since Linux 2.6.17)
              Stream socket peer closed connection, or shut down writing half of connection.  (This flag is especially useful for writing simple code to  detect  peer
              shutdown when using Edge Triggered monitoring.)

       EPOLLPRI
              There is urgent data available for read(2) operations.

       EPOLLERR
              Error condition happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.

       EPOLLHUP
              Hang  up happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.  Note that
       EPOLLOUT
              The associated file is available for write(2) operations.

       EPOLLRDHUP (since Linux 2.6.17)
              Stream socket peer closed connection, or shut down writing half of connection.  (This flag is especially useful for writing simple code to  detect  peer
              shutdown when using Edge Triggered monitoring.)

       EPOLLPRI
              There is urgent data available for read(2) operations.

       EPOLLERR
              Error condition happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.

       EPOLLHUP
              Hang  up happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.  Note that
              when reading from a channel such as a pipe or a stream socket, this event merely indicates that the peer closed its  end  of  the  channel.   Subsequent
              reads from the channel will return 0 (end of file) only after all outstanding data in the channel has been consumed.

       EPOLLET
              Sets the Edge Triggered behavior for the associated file descriptor.  The default behavior for epoll is Level Triggered.  See epoll(7) for more detailed
              information about Edge and Level Triggered event distribution architectures.

       EPOLLONESHOT (since Linux 2.6.2)
              Sets the one-shot behavior for the associated file descriptor.  This means that after an event is pulled out  with  epoll_wait(2)  the  associated  file
              descriptor  is  internally  disabled  and no other events will be reported by the epoll interface.  The user must call epoll_ctl() with EPOLL_CTL_MOD to
              rearm the file descriptor with a new event mask.

       EPOLLWAKEUP (since Linux 3.5)
              If EPOLLONESHOT and EPOLLET are clear and the process has the CAP_BLOCK_SUSPEND capability, ensure that the system does not enter "suspend"  or  "hiber‐
              nate"  while  this  event  is  pending  or being processed.  The event is considered as being "processed" from the time when it is returned by a call to
              epoll_wait(2) until the next call to epoll_wait(2) on the same epoll(7) file descriptor, the closure of that file descriptor, the removal of  the  event
              file descriptor with EPOLL_CTL_DEL, or the clearing of EPOLLWAKEUP for the event file descriptor with EPOLL_CTL_MOD.  See also BUGS.
 
		
	 
	epoll_wait(epollfd,...)等待直到注册的事件发生
	int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
 
	while(TRUE)
	{
		fds = epoll_wait();
		for(i=0; i < fds;i++)
		{
		//do something
		}
	}
 
********************************************************************/

/********************************************************************

并发编程方法:
1、ache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型
2、select模型和poll模型
3、epoll模型

********************************************************************/
#include"mylib.h"
#include<sys/epoll.h>
 
int ipv4_tcp_creat_socket(void)
{
	 int opt;
	 socklen_t len;
	 int listenfd;
	 struct sockaddr_in server;
 
	 if((listenfd = socket(AF_INET,SOCK_STREAM,0))<0)
	 {
		 perror("Creat socket failed\n");
		 return -1;
	 }
	 
	 //监听套接字,地址可重用
	 if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)))<0)
	 {
		 perror("Error,set socket reuse addr failed\n");
		 return -2;
	 }
	 
	 bzero(&server,sizeof(server));
	 server.sin_family	 = AF_INET;
	 server.sin_port = htons(SERV_PROT);
	 //server.sin_addr.s_addr = inet_addr("127.0.0.1");
	 //inet_pton(AF_INET,"127.0.0.1",&server.sin_addr);
	 server.sin_addr.s_addr =  htonl(INADDR_ANY);
	 
	 len = sizeof(struct sockaddr);
	 if(bind(listenfd,(struct sockaddr*)(&server),len)<0)
	 {
		 perror("bind error\n");
		 return -3;
	 }
	 
	 listen(listenfd,MAX_LISTEN_QUE);
	 
	 return listenfd;
}
 
int process_data(int sockfd)
{
	 int bytes;
	 char buf[MAX_BUFFER_SIZE];
	 char *s = buf;
	 char flag = 1;
	 int len = 0;
	 memset(buf,0,MAX_BUFFER_SIZE);
	 while(flag)
	 {
		 bytes = recv(sockfd,s,ReadLine,0);
		 
		 //如果是 ReadLine 个字节,继续去读
		 if(bytes == ReadLine)
		 {
		 	flag = 1;
		 }
		 //如果不是五个字节,就退出
		 else 
		 {
		 	flag = 0;
		 }

		 if(bytes<0)
		 {
			 //缓冲区没数据了
		 	 if(errno == EAGAIN)
		 	 {
		 	 	printf("no data\n");	
				break;
		 	 }
			 perror("read err\n");
			 return -1;
		 }
		 
		 if(bytes == 0)
		 {
			 printf("client connect closed\n");
			 //close(sockfd);
			 return -2;
		 }

		 //记录他读了多长数据
		 s += bytes;
		 len += bytes;
	 }
	 
	 printf("buf:%s,len:%d\n",buf,len);
	 send(sockfd,buf,len,0);
	 //memset(buf,0,MAX_BUFFER_SIZE);
	 return 0;
}
 
int main(int argc,char *argv[])
{
	 int epollfd,sockfd;
	 int listenfd;
	 struct epoll_event ev,events[MAX_EVENTS];
	 struct sockaddr_in client;
	 int len;
	 int i,rv,fds; 
 
	 len = sizeof(struct sockaddr_in);
	 
	 epollfd  = epoll_create(MAX_EVENTS);
	 if(epollfd < 0)
	 {
		 perror("epoll_create err:");
		 return -1;
	 } 
	 //监听套接字
	 listenfd = ipv4_tcp_creat_socket(); 
	 //将监听套接字 listenfd 变成非阻塞模式
	 fcntl(listenfd,F_SETFL,O_NONBLOCK);
 
	 ev.data.fd = listenfd;
	 ev.events	= EPOLLIN;
	 rv = epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&ev);
	 if(rv < 0)
	 {
		 perror("epoll_ctl err:");
		 return -1;
	 }
	 
	 while(1)
	 {
		 //-1:永远等待
		 fds = epoll_wait(epollfd,events,MAX_EVENTS,-1);
		 if(fds < 0)
		 {
			 perror("epoll_wait err:");
			 return -1;
		 }
		 for(i = 0;i < fds; i++)
		 {
		 	//连接事件
			 if(events[i].data.fd == listenfd)
			 {
				 sockfd = accept(listenfd,(struct sockaddr *)&client,&len);
				 if(sockfd < 0)
				 {
					 perror("accept err:");
					 continue;
				 }
				printf("sockfd = %d\n",sockfd);
				printf("IP:%s,Port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
				ev.data.fd = sockfd;
				//EPOLLET 边缘触发模式
				ev.events	= EPOLLIN | EPOLLET;
				epoll_ctl(epollfd,EPOLL_CTL_ADD,sockfd,&ev);
				continue;
			 }
			 else
			 {
				 rv = process_data(events[i].data.fd);
				 if(rv == -2)
				 {
					 epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
					 close(events[i].data.fd);
					 continue;
				 }
				 else
				 {
 
				 }
			 }
		 }
	 }	 
	 return 0;
}

实验结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值