0
点赞
收藏
分享

微信扫一扫

poll,epoll,select,poll与epoll的区别,LT模式与ET模式的区别

黎轩的闲暇时光 2022-04-07 阅读 82
c++

文章目录

一,poll

在这里插入图片描述

poll与select的区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

#define _GNU_SOURCE//POLLRDHUP的宏
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<poll.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<assert.h>


#define MAX 10

int socket_init();
void poll_fds_init(struct pollfd fds[])//将整个数组全部清零
{
   for(int i=0;i<MAX;++i)
   {
      fds[i].fd=-1;
      fds[i].events=0;
      fds[i].revents=0;
   }
}

void poll_fds_add(int fd,struct pollfd fds[])
{
    for(int i=0;i<MAX;++i)
    {
         if(fds[i].fd==-1)
         {
             fds[i].fd=fd;
             fds[i].events=POLLIN;//读事件
             fds[i].revents=0;//等到poll返回后poll会帮我们填充revents所以检查发生了哪些事件,就要检查revents中是否有我们注册的事件发生
             break;
         }
    }
}

void poll_fds_del(int fd,struct pollfd fds[])
{
    for(int i=0;i<MAX;++i)
    {
       if(fds[i].fd==fd)
       {
          fds[i].fd=-1;
          fds[i].events=0;
          fds[i].revents=0;
          break;
       }
    }
}

int main()
{
   int sockfd=socket_init();
   assert(sockfd!=-1);
   struct pollfd poll_fds[MAX];
   poll_fds_init(poll_fds);//清空数组
   poll_fds_add(sockfd,poll_fds);//

  while(1)
  {
     int n=poll(poll_fds,MAX,5000);//5000mspoll以ms为单位
     if(n<0)
     {
        printf("poll err\n");
     }
     else if(n==0)//poll返回值为0代表失败了
     {
         printf("time out\n");
     }
     else
     {
          for(int i=0;i<MAX;++i)//遍历数组
          {
                   if(poll_fds[i].fd==-1)
                   {
                             continue;
                   }
                   //如果没有以下代码,客端关闭但是服务器端依旧判断该描述符上有读事件,
                   if(poll_fds[i].revents & POLLRDHUP)//真则说明客户端已断开
                   {
                       close(poll_fds[i].fd);
                       poll_fds_del(poll_fds[i].fd,poll_fds);
                       printf("client hup\n");
                       continue;
                   }
                 
                   if(poll_fds[i].revents & POLLIN)//与,判断是否有读事件
                   {
                      if(poll_fds[i].fd==sockfd)
                      {
                          struct sockaddr_in caddr;//记录一个客户端ip接口的套接字地址结构
                          int len=sizeof(caddr);
                          int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
                          if(c<0)
                          {
                            continue;
                          }
                          printf("accept :%d\n",c);
                          poll_fds_add(c,poll_fds);
                      }
                      else
                      {
                          char buff[128]={0};
                          int num=recv(poll_fds[i].fd,buff,127,0);
                           // int num=recv(poll_fds[i].fd,buff,1,0);
                          if(num<=0)
                          {
                             close(poll_fds[i].fd);
                             poll_fds_del(poll_fds[i].fd,poll_fds);
                             printf("client close\n");
                          }
                          else
                          {
                             printf("recv(%d)=%s\n",poll_fds[i].fd,buff);
                             send(poll_fds[i].fd,"ok",2,0);
                          }
                      }
                   }
                   //if(poll_fds[i].revents*POLLOUT)
          }
     }
  }
}

int socket_init()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   if(sockfd==-1)
   {
     return -1;
   }
   struct sockaddr_in saddr;
   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));
   if(res==-1)
   {
      return -1;
   }

    res=listen(sockfd,5);
    if(res==-1)
    {
       return -1;
    }

   return sockfd;
   
}

                 

只接收一个数据时候的情况,和select情况一样,读了多少次就返回多少个OK
在这里插入图片描述

二,epoll

应对描述符多的

select,poll 与epoll的区别

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

day22
epoll代码

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

#define MAX 10

int socket_init();
void epoll_add(int epfd,int fd)
{
    struct  epoll_event ev;
    ev.data.fd=fd;
    ev.events=EPOLLIN|EPOLLEY;//读事件
    if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev)==-1)
    {
        printf("epoll ctl add err\n");
        
    }
}
void epoll_del(int epfd,int fd)
{
    if(epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL)==-1)
    {
       perror("epoll ctl del err\n");
    }
}
int main()
{
   int sockfd=socket_init();
   assert(sockfd!=-1);
   int epfd=epoll_create(MAX);//内核事件表
   assert(epfd!=-1);
    epoll_add(epfd,sockfd);将监听套接字添加到内核事件表
    struct epoll_event evs[MAX];收集就绪描述符
    while(1)
    {
        int n=epoll_wait(epfd,evs,MAX,5000);//阻塞获取就绪描述符
        if(n==-1)
        {
           printf("epoll wait err\n");
        }else if(n==0)
        {
           printf("time out\n");
        }else
        {
           for(int i=0;i<n;++i)
           {
              int fd=evs[i].data.fd;
              if(evs[i].events & EPOLLIN)//有读事件
              {
                if(fd==sockfd)
                {
                   struct sockaddr_in caddr;
                   int len=sizeof(caddr);
                   int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
                   if(c<0)
                   {
                      continue;
                   }
                   printf("accept c=%d\n",c);
                   epoll_add(epfd,c);
                }else
                {
                  char buff[128]={0};
                  int num=recv(fd,buff,127,0);
                  if(num<=0)
                  {//注意顺序,必须先移除fd(移除时用到了该文件描述符,所以不能先close(fd),但是select和poll不必在意),在关闭fd
                     epoll_del(epfd,fd);
                     close(fd);
                     printf("client close\n");
                  }else
                  {
                      printf("recv(%d)=%s\n",fd,buff);
                      send(fd,"ok",2,0);
                  }
                }
              }
           }
        }
        
    }
}

int socket_init()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   if(sockfd==-1)
   {
     return -1;
   }
   struct sockaddr_in saddr;
   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));
   if(res==-1)
   {
      return -1;
   }

    res=listen(sockfd,5);
    if(res==-1)
    {
       return -1;
    ]

   return sockfd;
   
}

ET模式epoll代码

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

int socket_init();
void setnonblock(int fd)
{
 int oldfl=fcntl(fd,F_GETFL);
 int newfl=oldfl|O_NONBLOCK;//设置为阻塞,然后循环读取
 if(fcntl(fd,F_SETFL,newfl)==-1)
 {
  printf("fcntl err\n");
 }
}
void epoll_add(int epfd,int fd)
{
    struct  epoll_event ev;
    ev.data.fd=fd;
    ev.events=EPOLLIN|EPOLLEY;//读事件
    //ev.events=EPOLLIN|EPOLLEY;//读事件|ET模式的设置
    if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev)==-1)
    {
        printf("epoll ctl add err\n");
    }
    setnonblock(fd);
}
void epoll_del(int epfd,int fd)
{
    if(epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL)==-1)
    {
       perror("epoll ctl del err\n");
    }
}
int main()
{
   int sockfd=socket_init();
   assert(sockfd!=-1);
   int epfd=epoll_create(MAX);//内核事件表
   assert(epfd!=-1);
    epoll_add(epfd,sockfd);将监听套接字添加到内核事件表
    struct epoll_event evs[MAX];收集就绪描述符
    while(1)
    {
        int n=epoll_wait(epfd,evs,MAX,5000);//阻塞获取就绪描述符
        if(n==-1)
        {
           printf("epoll wait err\n");
        }else if(n==0)
        {
           printf("time out\n");
        }else
        {
           for(int i=0;i<n;++i)
           {
              int fd=evs[i].data.fd;
              if(evs[i].events & EPOLLIN)//有读事件
              {
                if(fd==sockfd)
                {
                   struct sockaddr_in caddr;
                   int len=sizeof(caddr);
                   int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
                   if(c<0)
                   {
                      continue;
                   }
                   printf("accept c=%d\n",c);
                   epoll_add(epfd,c);
                }else
                {
                  while(1)
                  {
                     char buff[128]={0};
                     int num=recv(fd,buff,1,0)l
                     if(num==-1)
                     {
                       if(errno==EAGAINT ||erno== EWOULDBLOCK)//等于他就说明非阻塞模式下,没有可读的数据产生的错误
                       {
                        send(fd,"ok",2,0);
                       }
                       else
                       {
                         printf("recv err");
					   }
                     }
                      else if(num==0)
                      {
                        epoll_del(epdf,fd);
                        close(fd);
                        printf("client close\n");
                        break;
					  }
					  else
					  {
					   printf("buff=%s\n",buff);
					  }
                  }
                }
              }
           }
        }
        
    }
}

int socket_init()
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   if(sockfd==-1)
   {
     return -1;
   }
   struct sockaddr_in saddr;
   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));
   if(res==-1)
   {
      return -1;
   }

    res=listen(sockfd,5);
    if(res==-1)
    {
       return -1;
    ]

   return sockfd;
   
}

LT模式与ET模式的区别

举报

相关推荐

0 条评论