epoll学习总结第一篇

epoll
1. et模式:socket状态改变:缓冲区收到数据、关闭socket、,epoll_wait返回通知一次,不论是否接收完毕仅且通知一次,
例如:客户端发送数据:”hello world!“
      服务端epoll_wait返回一次通知,然后recv 5个字节,接收到的是”hello“,此时缓冲区剩余数据为:“ world!”,然后继续epoll_wait,此时不会收到任何通知(即epoll_wait不会返回)
      客户端如下操作会引起服务端收到通知:
      a。客户端继续写数据到此socket,socket状态改变,服务端epoll_wait返回通知
      b。客户端关闭socket,socket状态改变,服务端epoll_wait返回通知
      服务端如下操作,epoll_wait也会产生通知
      a。在数据未接收完毕时,将socket从epoll队列删除然后再添加(此时socket缓冲区必须有数据,不管是新数据还是上次未接收完毕剩余的数据)
        即对socket执行删除epoll_ctl_del,添加epoll_ctl_add操作时epoll_wait会返回一次通知,这相当于socket重新加入epoll队列,而此时socket的缓冲区还保留上次接收剩余的数据,于是epoll_wait返回通知

 

实现步骤:

客户端:

1. 直接写”hello world!“ 12个字节

 

服务端关键代码:

1. 创建epoll描述符,监听socket加入epoll监听队列

epoll_fd = epoll_create(EPOLL_MAX_SOCKETS);
  if(epoll_fd == -1)
  {
    perror("init epoll fd error");
    printf("End at: %d\n", __LINE__);
    exit(1);
  }
  ev.events = EPOLLIN | EPOLLET;
  ev.data.fd = listenfd;
  if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenfd, &ev) <0)
  {
    perror("epoll ctl error");
    printf("End at:%d\n", __LINE__);
    exit(1);
  }

2. epoll等待事件发生,处理客户端连接

int flag = 0;
  while(1)
  {
    int nfds = epoll_wait(epoll_fd, events, EPOLL_MAX_SOCKETS, 1000/*timeout*/);
    if(nfds == -1)
    {
      perror("epoll_wait error.");
      printf("End at:%d\n", __LINE__);
      continue;
    }

    int j = 0;
    int i = 0;
    for(i = 0; i < nfds; ++i)
    {
      if(listenfd == events[i].data.fd)
      {
        sockConnect = accept(events[i].data.fd, (struct sockaddr*)&remoteAddr, &addrLen);
        if(sockConnect == -1)
        {
          perror("accept error");
          printf("End at:%d\n", __LINE__);
          continue;
        }

        printf("accepted a connection, at line %d\n", __LINE__);

        setnonblocking(sockConnect); 
        ev.events = EPOLLIN|EPOLLET;  //设置ET模式
        ev.data.fd = sockConnect;
        if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockConnect, &ev) == -1) //新socket加入epoll监听队列
        {
          perror("accept error");
          printf("End at:%d\n", __LINE__);
          return -1;
        }
      }
      else
      {

      {
        int r=0;
        pthread_t tid = 0;
        r = pthread_create(&tid, NULL, recv_thread, (void *)&events[i].data.fd); //创建线程处理socket

      }
    }
  }

3. 接收线程函数处理接收到的socket

void *recv_thread(void *data)
{
  int sock = *(int*)data;
  char buf[1024];
  struct epoll_event ev;
 
  memset(buf, 0, sizeof(buf));
  
 /* while(1)
  {*/
    int r = recv(sock, buf, 5, 0); //仅接收5个字节”hello“, 剩余” world!“,此时客户端再发送任意字节数据或者关闭socket,就会触发读事件,再次执行该行时就会返回剩余数据的前5字节” worl“。
    if(r == -1)
    {
      //perror("recv error");
      if(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
      {
        printf("recv error: %d, recv_thread exited. errno: %d, errmsg:%s\n", r, errno, strerror(errno));
        sleep(1);
        continue;
      }
      else
      {
        printf("recv error: %d, recv_thread exited. errno: %d, errmsg:%s\n", r, errno, strerror(errno));
        break;
      }
    }
    if(r == 0)
    {
      close(sock);
      printf("socket colsed: %d, recv_thread exited.\n", r);
      return NULL;
    }
    buf[r] = '\0';
    if(r != 0)
      printf("recv_thread recved:%s\n", buf);

    /*break;  

    }*/
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

种菜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值