Linux c++(socket网络通信 & epoll)

监听读缓冲区的变化

  • 【LT】水平模式: 只要读缓冲区有数据就会触发epoll_wait
  • 【ET】边沿触发: 数据来一次,epoll_wait只触发一次

监听写缓冲区的变化

  • 水平模式: 只要可以写,就会触发
  • 边沿触发: 数据从有到无,就会触发
epoll

#include <sys/epoll.h>

  • 三个函数:
    • 该函数生成一个epoll专门的文件描述符

    • int epoll_creae(int size);

      • size: epoll上能关注的最大描述符数(监听的文件描述符的上限,2.6版本之后写1即可)
    • 用于控制某个epoll文件描述符事件,可以注册,修改,删除

    • int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event);

      • epfd: epoll_create生成的epoll专用描述符
      • op:
        • EPOLL_CTL_ADD ---注册
        • EPOLL_CTL_MOD ---修改
        • EPOLL_CTL_DEL ---删除
      • fd: 关联的文件描述符
      • event: 告诉内核要监听什么事件
        • EPOLLIN -读
        • EPOLLOUT -写
        • EPOLLERR -异常
    • 等待IO事件发生-可以设置阻塞的函数

    • int epoll_wait(
      int epfd, //要检测的句柄
      struct epoll_event* events, //用于回传待处理事件的数组
      int maxevnets, //告诉内核这个events的大小
      int timeout); //为超时时间 -1:永久阻塞 0:立即返回 >0:等待的时长毫秒
      对应select和poll函数
      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_data_t data;
}
  #include <stdio.h>                                                           
  #include <sys/types.h>
  #include <arpa/inet.h> 
  #include <string.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/epoll.h>
  int main(int argc,char *argv[]){        
      struct sockaddr_in serv_addr;
      socklen_t serv_len = sizeof(serv_addr);
      //    int port = atoi(a);
      //创建套接字
      int lfd = socket(AF_INET,SOCK_STREAM,0);
      //初始化服务器
      memset(&serv_addr,0,serv_len);
      serv_addr.sin_family=AF_INET;
      serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      serv_addr.sin_port = htons(8888);
      //绑定IP和端口
      bind(lfd,(struct sockaddr*)&serv_addr,serv_len);
      //设置同时监听的最大个数
      listen(lfd,36);
      printf("Start accept ......\n");
  
      struct sockaddr_in client_addr;
      socklen_t cli_len = sizeof(client_addr);
  
      // 创建epoll树根节点
      int epfd = epoll_create(1);
      // 初始化
      struct epoll_event ev;
      ev.events = EPOLLIN;
      ev.data.fd = lfd;
      epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev);
      struct epoll_event all[2000];
      while(1)
      {    
          // 使用epoll通知内核fd 文件IO检测
          int ret = epoll_wait(epfd,all,sizeof(all)/sizeof(all[0]),-1);
          if(ret == -1)
          {
              perror("epoll_wait error");
              break;
          }else if(ret == 0)
          {
              continue;
          }else{ // 有变化
              // 便利all数组是否有新连接
              for(int i = 0;i<ret;++i)
              {
                  int fd = all[i].data.fd;   
                  // 判断是否有新链接,并且读事件变化
                  if(fd == lfd && all[i].events & EPOLLIN)
                  {
                      int cfd = accept(lfd,(struct sockaddr*)&client_addr,&cli_
                      if(cfd == -1)
                      {
                          perror("accept error");
                          continue;
                      }
                      // 将新cfd挂载到树上
                      ev.events = EPOLLIN;
                      ev.data.fd = cfd;
                      epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
                  }else if(all[i].events & EPOLLIN){ //cfd变化,而且是读事件变>
  
                      // 处理已经连接的客户端发来的数据
                      char buf[1024] = {0};
                      int len = recv(fd,buf,sizeof(buf),0);
                      if (len <0) {
                          perror("recv error");
                          close(fd);
                          epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&all[i]);
                          continue;
                      }else if(len == 0)
                      {   
                          printf("客户端断开连接\n");
                          close(fd);
                          epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&all[i]);            
                      }else{
                          printf("recv %s\n",buf);
                          send(fd,buf,len,0);
                      }   
                  }   
              }   
          }   
  }
  close(lfd);
  return 0;
  }

posted on 2021-05-10 09:37  lodger47  阅读(258)  评论(0)    收藏  举报

导航