欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信

程序员文章站 2022-03-10 15:10:19
linux epoll系列2 利用epoll_wait查看是否可以送信 write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变成了阻塞了,这个进程或者线程就堵住了,不能被响应了。 epoll_wait函数可以判断出,缓存区是否 ......

linux epoll系列2 利用epoll_wait查看是否可以送信

write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变成了阻塞了,这个进程或者线程就堵住了,不能被响应了。

epoll_wait函数可以判断出,缓存区是否可写,可写后再调用write函数,这样就避免了write函数被阻塞。

例子1,是接收端。

例子2, 是会发生阻塞的发送端。

例子3,利用了epoll_wait,所以是不会发生阻塞的。

例子1,接收端

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

int main(){
  int sock0;
  sockaddr_in addr;
  sockaddr_in client;
  socklen_t len;
  int sock;
  int n;
  char buf[65536];
  int i;

  sock0 = socket(af_inet, sock_stream, 0);

  addr.sin_family = af_inet;
  addr.sin_port = htons(12345);
  addr.sin_addr.s_addr = inaddr_any;
  bind(sock0, (sockaddr*)&addr, sizeof(addr));

  listen(sock0, 5);

  len = sizeof(client);
  sock = accept(sock0, (sockaddr*)&client, &len);

  printf("after accept\n");

  for(i = 0; i < 10; ++i){
    sleep(2);
    n = read(sock, buf, sizeof(buf));
    printf("recv data size:[%d] bytes\n", n);
  }

  printf("close socket and finish\n");

  close(sock);

  return 0;
}

例子2, 是会发生阻塞的发送端。

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

int main(){
  sockaddr_in server;
  int sock;
  char buf[65536];
  int n;

  sock = socket(af_inet, sock_stream, 0);

  server.sin_family = af_inet;
  server.sin_port = htons(12345);

  inet_pton(af_inet, "127.0.0.1", &server.sin_addr.s_addr);

  n = connect(sock, (sockaddr*)&server, sizeof(server));
  if(n != 0){
    perror("connect");
    return 1;
  }

  int cnt = 0;
  while(1){
    ++cnt;
    printf("[%d]write %ld bytes\n", cnt, sizeof(buf));
    n = write(sock, buf, sizeof(buf));
    if(n <= 0){
      printf("write error:%d\n", n);
      break;
    }
  }

  close(sock);

  return 0;
  
}

例子3,利用了epoll_wait,所以是不会发生阻塞的。

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

#define events 12

int main(){
  sockaddr_in server;
  epoll_event ev, ev_ret[events];
  int sock, epfd;
  char buf[65536];
  int nfds;
  int n;

  sock = socket(af_inet, sock_stream, 0);

  server.sin_family = af_inet;
  server.sin_port = htons(12345);

  inet_pton(af_inet, "127.0.0.1", &server.sin_addr.s_addr);

  n = connect(sock, (sockaddr*)&server, sizeof(server));
  if(n != 0){
    perror("connect");
    return 1;
  }

  epfd = epoll_create(2);
  if(epfd < 0){
    perror("epfd");
    return 1;
  }

  memset(&ev, 0, sizeof(ev));
  ev.events = epollout;//可写
  ev.data.fd = sock;
  if(epoll_ctl(epfd, epoll_ctl_add, sock, &ev) != 0){
    perror("epoll_clt");
    return 1;
  }

  int cnt = 0;
  while(1){
    cnt++;
    printf("before epoll wait\n");

    nfds = epoll_wait(epfd, ev_ret, events, -1);
    if(nfds < 0){
      perror("epoll_wait");
      return 1;
    }

    printf("after epoll_wait\n");

    if(ev_ret[0].data.fd == sock){
      printf("[%d]write %ld types\n", cnt, sizeof(buf));

      n = write(sock, buf, sizeof(buf));
      if(n <= 0){
    printf("write error:%d\n", n);
    break;
      }
    }
  }

  close(sock);
  return 0;
}

运行方法:先运行接收端,再运行阻塞发送端。

从运行结果可以看出:阻塞的发送端,缓存区溢出后,write函数变成阻塞的了。

运行方法:先运行接收端,再运行非阻塞发送端。

从运行结果可以看出:非阻塞的发送端,缓存区溢出后,write函数是没有被调用的。

c/c++ 学习互助qq群:877684253

c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信

本人微信:xiaoshitou5854