• c/c++ linux epoll系列1 创建epoll


    linux epoll系列1 创建epoll

    据说select和poll的弱点是,随着连接(socket)的增加,性能会直线下降。

    epoll不会随着连接(socket)的增加,性能直线下降。

    知识点:

    1,epoll_wait函数是阻塞的,直到有socket发生变化。

    2,epoll使用流程,先创建(epoll_create),再把socket添加到epoll里(epoll_ctl),然后等待socket的变化(epoll_wait)

    接收端,接收2个socket

    #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(){
      int sock1, sock2;
      sockaddr_in addr1, addr2;
      int epfd;
      epoll_event ev, ev_ret[EVENTS];
      char buf[2048];
      int i;
      int nfds;
      int n;
    
      //创建2个接受消息的socket
      sock1 = socket(AF_INET, SOCK_DGRAM, 0);
      sock2 = socket(AF_INET, SOCK_DGRAM, 0);
      addr1.sin_family = AF_INET;
      addr2.sin_family = AF_INET;
    
      inet_pton(AF_INET, "127.0.0.1", &addr1.sin_addr.s_addr);
      inet_pton(AF_INET, "127.0.0.1", &addr2.sin_addr.s_addr);
    
      addr1.sin_port = htons(11111);
      addr2.sin_port = htons(22222);
    
      bind(sock1, (sockaddr*)&addr1, sizeof(addr1));
      bind(sock2, (sockaddr*)&addr2, sizeof(addr2));
    
      //参数不小于0就行
      epfd = epoll_create(1);
      if(epfd < 0){
        perror("epoll_create");
        return 1;
      }
    
      memset(&ev, 0, sizeof(ev));
      ev.events = EPOLLIN;//只读
      ev.data.fd = sock1;//把sock1加到epoll
      if(epoll_ctl(epfd, EPOLL_CTL_ADD, sock1, &ev) != 0){
        perror("epoll_ctl");
        return 1;
      }
    
      memset(&ev, 0, sizeof(ev));
      ev.events = EPOLLIN;//只读
      ev.data.fd = sock2;//把sock2加到epoll
      if(epoll_ctl(epfd, EPOLL_CTL_ADD, sock2, &ev) != 0){
        perror("epoll_ctl");
        return 1;
      }
    
      while(1){
        printf("before epoll_wait
    ");
        //在这里会阻塞,直到有socket进来.
        nfds = epoll_wait(epfd, ev_ret, EVENTS, -1);
        if(nfds <= 0){
          perror("epoll_wait");
          return 1;
        }
    
        printf("after epoll_wait
    ");
    
        for(i = 0; i < nfds; ++i){
          //判断进来的socket是哪个socket
          if(ev_ret[i].data.fd == sock1){
    	//从sock1读取数据,并写入到标准输出
    	n = recv(sock1, buf, sizeof(buf), 0);
    	write(fileno(stdout), buf, n);
          }
          //判断进来的socket是哪个socket
          else if(ev_ret[i].data.fd == sock2){
    	//从sock1读取数据,并写入到标准输出
    	n = recv(sock2, buf, sizeof(buf), 0);
    	write(fileno(stdout), buf, n);
          }
        }
      }
    
      close(sock1);
      close(sock2);
      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(){
      int sock;
      sockaddr_in dest1, dest2;
      char buf[1024];
    
      sock = socket(AF_INET, SOCK_DGRAM, 0);
    
      dest1.sin_family = AF_INET;
      dest2.sin_family = AF_INET;
    
      inet_pton(AF_INET, "127.0.0.1", &dest1.sin_addr.s_addr);
      inet_pton(AF_INET, "127.0.0.1", &dest2.sin_addr.s_addr);
    
      dest1.sin_port = htons(11111);
      dest2.sin_port = htons(22222);
    
      strcpy(buf, "data to port 11111
    ");
      //给地址1(dest1)送信
      sendto(sock, buf, strlen(buf), 0, (sockaddr*)&dest1, sizeof(dest1));
      
      strcpy(buf, "data to port 22222
    ");
      //给地址2(dest2)送信
      sendto(sock, buf, strlen(buf), 0, (sockaddr*)&dest2, sizeof(dest1));
    
      close(sock);
    
      return 0;
    }
    
    

    github源代码

    运行方法:

    先运行接收端,结果如下:

    before epoll_wait
    

    再运行发送端,结果如下:

    before epoll_wait
    after epoll_wait
    data to port 11111
    before epoll_wait
    after epoll_wait
    data to port 22222
    before epoll_wait
    

    从运行结果可以看出:在epoll_wait处,程序的停住的,也就是阻塞的状态,但是当运行发送端后,马上就变成了非阻塞状态,也就实现了,处理多个socket的请求,而并没有使用多进程,或者多线程。

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

    本人微信:xiaoshitou5854

  • 相关阅读:
    MyEclipse使用经验总结
    CSDN-markdown编辑器使用简介
    struts2提供的校验器
    JUnit4 中@AfterClass @BeforeClass @after @before的区别对比
    JAVA中文字符编码问题详解 控制台输出
    Statement、PreparedStatement
    struts2 文件上传
    SQL RIGHT JOIN 关键字:语法及案例剖析
    SQL LEFT JOIN 关键字:语法及案例剖析
    SQL INNER JOIN 关键字:语法及案例剖析
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/9824439.html
Copyright © 2020-2023  润新知