• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Linux IO多路复用之epoll网络编程

    前言

    本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:

    服务端

    代码如下:

    #include <unistd.h>
    #include <sys/types.h>    /* basic system data types */
    #include <sys/socket.h>   /* basic socket definitions */
    #include <netinet/in.h>   /* sockaddr_in{} and other Internet defns */
    #include <arpa/inet.h>    /* inet(3) functions */
    #include <sys/epoll.h> /* epoll function */
    #include <fcntl.h>   /* nonblocking */
    #include <sys/resource.h> /*setrlimit */
    #include <stdlib.h>
    #include <errno.h>
    #include <stdio.h>
    #include <string.h>
    #define MAXEPOLLSIZE 10000
    #define MAXLINE 10240
    int handle(int connfd);
    int setnonblocking(int sockfd)
    {
      if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
        return -1;
      }
      return 0;
    }
    int main(int argc, char **argv)
    {
      int servPort = 6888;
      int listenq = 1024;
      int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = 0;
      struct sockaddr_in servaddr, cliaddr;
      socklen_t socklen = sizeof(struct sockaddr_in);
      struct epoll_event ev;
      struct epoll_event events[MAXEPOLLSIZE];
      struct rlimit rt;
      char buf[MAXLINE];
      /* 设置每个进程允许打开的最大文件数 */
      rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
      if (setrlimit(RLIMIT_NOFILE, &rt) == -1) 
      {
        perror("setrlimit error");
        return -1;
      }
      bzero(&servaddr, sizeof(servaddr));
      servaddr.sin_family = AF_INET; 
      servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
      servaddr.sin_port = htons (servPort);
      listenfd = socket(AF_INET, SOCK_STREAM, 0); 
      if (listenfd == -1) {
        perror("can't create socket file");
        return -1;
      }
      int opt = 1;
      setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
      if (setnonblocking(listenfd) < 0) {
        perror("setnonblock error");
      }
      if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1) 
      {
        perror("bind error");
        return -1;
      } 
      if (listen(listenfd, listenq) == -1) 
      {
        perror("listen error");
        return -1;
      }
      /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
      kdpfd = epoll_create(MAXEPOLLSIZE);
      ev.events = EPOLLIN | EPOLLET;
      ev.data.fd = listenfd;
      if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0) 
      {
        fprintf(stderr, "epoll set insertion error: fd=%d\n", listenfd);
        return -1;
      }
      curfds = 1;
      printf("epollserver startup,port %d, max connection is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq);
      for (;;) {
        /* 等待有事件发生 */
        nfds = epoll_wait(kdpfd, events, curfds, -1);
        if (nfds == -1)
        {
          perror("epoll_wait");
          continue;
        }
        /* 处理所有事件 */
        for (n = 0; n < nfds; ++n)
        {
          if (events[n].data.fd == listenfd) 
          {
            connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&socklen);
            if (connfd < 0) 
            {
              perror("accept error");
              continue;
            }
            sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
            printf("%d:%s", ++acceptCount, buf);
    
            if (curfds >= MAXEPOLLSIZE) {
              fprintf(stderr, "too many connection, more than %d\n", MAXEPOLLSIZE);
              close(connfd);
              continue;
            } 
            if (setnonblocking(connfd) < 0) {
              perror("setnonblocking error");
            }
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = connfd;
            if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
            {
              fprintf(stderr, "add socket '%d' to epoll failed: %s\n", connfd, strerror(errno));
              return -1;
            }
            curfds++;
            continue;
          } 
          // 处理客户端请求
          if (handle(events[n].data.fd) < 0) {
            epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
            curfds--;
          }
        }
      }
      close(listenfd);
      return 0;
    }
    int handle(int connfd) {
      int nread;
      char buf[MAXLINE];
      nread = read(connfd, buf, MAXLINE);//读取客户端socket流
      if (nread == 0) {
        printf("client close the connection\n");
        close(connfd);
        return -1;
      } 
      if (nread < 0) {
        perror("read error");
        close(connfd);
        return -1;
      }  
      write(connfd, buf, nread);//响应客户端 
      return 0;
    }

    编译

    编译和启动服务端

    gcc epollserver.c -o epollserver
    ./epollserver

    总结

    以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

    上一篇:Linux环境下使用glog日志库的方法
    下一篇:Docker实现同Ip网段联通的实现
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    Linux IO多路复用之epoll网络编程 Linux,多路,复,用之,epoll,