zoukankan      html  css  js  c++  java
  • Linux 服务器IO模型 epoll

    epoll模型

    #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
    ", listenfd);
            return -1;
        }
        curfds = 1;
    
        printf("epollserver startup,port %d, max connection is %d, backlog is %d
    ", 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
    ", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
                    printf("%d:%s", ++acceptCount, buf);
    
                    if (curfds >= MAXEPOLLSIZE) {
                        fprintf(stderr, "too many connection, more than %d
    ", 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
    ", 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
    ");//nread==0为客户端正常调用函数closesocket
            close(connfd);
            return -1;
        } 
        if (nread < 0) {
            perror("read error");//nread<0为客户端杀进程
            close(connfd);
            return -1;
        }    
        write(connfd, buf, nread);//响应客户端  
        return 0;
    }

    关于ET、LT两种工作模式:
    ET模式仅当状态发生变化的时候才获得通知,这里所谓的状态的变化并不包括缓冲区中还有未处理的数据,也就是说,如果要采用ET模式,需要一直read/write直到出错为止,很多人反映为什么采用ET模式只接收了一部分数据就再也得不到通知了,大多因为这样;而LT模式是只要有数据没有处理就会一直通知下去的.

  • 相关阅读:
    selenium与表格的二三事
    ABP使用Mysql数据库
    Asp.net Mvc 使用EF6 code first 方式连接MySQL总结
    MVC后台数据赋值给前端JS对象
    Entity Framework 6 Code First 实践系列(1):实体类配置总结
    用git extensions clone项目时提示此主机的指纹不是由putty注册的解决办法
    AutoMapper5.0的用法
    StackExchange.Redis helper访问类封装
    Github上十大c#开源项目排行榜
    vs2015使用GIt连接git.oschina.net/
  • 原文地址:https://www.cnblogs.com/unreal/p/3870415.html
Copyright © 2011-2022 走看看