1. 程式人生 > >c/c++ linux epoll系列2 利用epoll_wait檢視是否可以送信

c/c++ linux epoll系列2 利用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;
}

github原始碼

例子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;
  
}

github原始碼

例子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;
}

github原始碼

執行方法:先執行接收端,再執行阻塞傳送端。

從執行結果可以看出:阻塞的傳送端,快取區溢位後,write函式變成阻塞的了。

執行方法:先執行接收端,再執行非阻塞傳送端。

從執行結果可以看出:非阻塞的傳送端,快取區溢位後,write函式是沒有被呼叫的。

c/c++ 學習互助QQ群:877684253

本人微信:xiaoshitou5854