• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天下

            記錄修行的印記

            epoll使用

            epoll使用

            在linux的網絡編程中,很長的時間都在使用select來做事件觸發。在linux新的內核中,有了一種替換它的機制,就是epoll。
            相比于select,epoll最大的好處在于它不會隨著監聽fd數目的增長而降低效率。因為在內核中的select實現中,它是采用輪詢來處理的,輪詢的fd數目越多,自然耗時越多。并且,在linux
            /posix_types.h頭文件有這樣的聲明:
            #define __FD_SETSIZE    1024
            表示select最多同時監聽1024個fd,當然,可以通過修改頭文件再重編譯內核來擴大這個數目,但這似乎并不治本。

            epoll的接口非常簡單,一共就三個函數:
            1int epoll_create(int size);
            創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大。這個參數不同于select()中的第一個參數,給出最大監聽的fd
            +1的值。需要注意的是,當創建好epoll句柄后,它就是會占用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll后,必須調用close()關閉。


            2int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
            epoll的事件注冊函數,它不同與select()是在監聽事件時告訴內核要監聽什么類型的事件,而是在這里先注冊要監聽的事件類型。第一個參數是epoll_create()的返回值,第二個參數表示動作,用三個宏來表示:
            EPOLL_CTL_ADD:注冊新的fd到epfd中;
            EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;
            EPOLL_CTL_DEL:從epfd中刪除一個fd;
            第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什么事,
            struct epoll_event結構如下:

            typedef union epoll_data {
                
            void *ptr;
                
            int fd;
                __uint32_t u32;
                __uint64_t u64;
            } epoll_data_t;

            struct epoll_event {
                __uint32_t events; 
            /* Epoll events */
                epoll_data_t data; 
            /* User data variable */
            };

            events可以是以下幾個宏的集合:
            EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
            EPOLLOUT:表示對應的文件描述符可以寫;
            EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);
            EPOLLERR:表示對應的文件描述符發生錯誤;
            EPOLLHUP:表示對應的文件描述符被掛斷;
            EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的。
            EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里


            3int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
            等待事件的產生,類似于select()調用。參數events用來從內核得到事件的集合,maxevents告之內核這個events有多大,這個 maxevents的值不能大于創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,
            -1阻塞)。該函數返回需要處理的事件數目,如返回0表示已超時。


            4、關于ET、LT兩種工作模式:
            可以得出這樣的結論:
            ET模式僅當狀態發生變化的時候才獲得通知,這里所謂的狀態的變化并不包括緩沖區中還有未處理的數據,也就是說,如果要采用ET模式,需要一直read
            /write直到出錯為止,很多人反映為什么采用ET模式只接收了一部分數據就再也得不到通知了,大多因為這樣;而LT模式是只要有數據沒有處理就會一直通知下去的.


            那么究竟如何來使用epoll呢?其實非常簡單。
            通過在包含一個頭文件#include 
            <sys/epoll.h> 以及幾個簡單的API將可以大大的提高你的網絡服務器的支持人數。

            首先通過create_epoll(
            int maxfds)來創建一個epoll的句柄,其中maxfds為你epoll所支持的最大句柄數。這個函數會返回一個新的epoll句柄,之后的所有操作將通過這個句柄來進行操作。在用完之后,記得用close()來關閉這個創建出來的epoll句柄。

            之后在你的網絡主循環里面,每一幀的調用epoll_wait(
            int epfd, epoll_event events, int max events, int timeout)來查詢所有的網絡接口,看哪一個可以讀,哪一個可以寫了?;镜恼Z法為:
            nfds 
            = epoll_wait(kdpfd, events, maxevents, -1);
            其中kdpfd為用epoll_create創建之后的句柄,events是一個epoll_event
            *的指針,當epoll_wait這個函數操作成功之后,epoll_events里面將儲存所有的讀寫事件。max_events是當前需要監聽的所有socket句柄數。最后一個timeout是 epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件范圍,為任意正整數的時候表示等這么長的時間,如果一直沒有事件,則范圍。一般如果網絡主循環是單獨的線程的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個線程的話,則可以用0來保證主循環的效率。

            epoll_wait范圍之后應該是一個循環,遍利所有的事件。

            幾乎所有的epoll程序都使用下面的框架:

                
            for( ; ; )
                {
                    nfds 
            = epoll_wait(epfd,events,20,500);
                    
            for(i=0;i<nfds;++i)
                    {
                        
            if(events[i].data.fd==listenfd) //有新的連接
                        {
                            connfd 
            = accept(listenfd,(sockaddr *)&clientaddr, &clilen); //accept這個連接
                            ev.data.fd=connfd;
                            ev.events
            =EPOLLIN|EPOLLET;
                            epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,
            &ev); //將新的fd添加到epoll的監聽隊列中
                        }
                        
            else if( events[i].events&EPOLLIN ) //接收到數據,讀socket
                        {
                            n 
            = read(sockfd, line, MAXLINE)) < 0    //
                            ev.data.ptr = md;     //md為自定義類型,添加數據
                            ev.events=EPOLLOUT|EPOLLET;
                            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,
            &ev);//修改標識符,等待下一個循環時發送數據,異步處理的精髓
                        }
                        
            else if(events[i].events&EPOLLOUT) //有數據待發送,寫socket
                        {
                            
            struct myepoll_data* md = (myepoll_data*)events[i].data.ptr;    //取數據
                            sockfd = md->fd;
                            send( sockfd, md
            ->ptr, strlen((char*)md->ptr), 0 );        //發送數據
                            ev.data.fd=sockfd;
                            ev.events
            =EPOLLIN|EPOLLET;
                            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,
            &ev); //修改標識符,等待下一個循環時接收數據
                        }
                        
            else
                        {
                            
            //其他的處理
                        }
                    }
                }



            epoll 
            - I/event notification facility

            /* Copyright (C) 2002-2006, 2007 Free Software Foundation, Inc.
               This file is part of the GNU C Library.

               The GNU C Library is free software; you can redistribute it and/or
               modify it under the terms of the GNU Lesser General Public
               License as published by the Free Software Foundation; either
               version 2.1 of the License, or (at your option) any later version.

               The GNU C Library is distributed in the hope that it will be useful,
               but WITHOUT ANY WARRANTY; without even the implied warranty of
               MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
               Lesser General Public License for more details.

               You should have received a copy of the GNU Lesser General Public
               License along with the GNU C Library; if not, write to the Free
               Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
               02111-1307 USA.  
            */

            #ifndef    _SYS_EPOLL_H
            #define    _SYS_EPOLL_H    1

            #include 
            <stdint.h>
            #include 
            <sys/types.h>

            /* Get __sigset_t.  */
            #include 
            <bits/sigset.h>

            #ifndef __sigset_t_defined
            # define __sigset_t_defined
            typedef __sigset_t sigset_t;
            #endif


            enum EPOLL_EVENTS
              {
                EPOLLIN 
            = 0x001,
            #define EPOLLIN EPOLLIN
                EPOLLPRI 
            = 0x002,
            #define EPOLLPRI EPOLLPRI
                EPOLLOUT 
            = 0x004,
            #define EPOLLOUT EPOLLOUT
                EPOLLRDNORM 
            = 0x040,
            #define EPOLLRDNORM EPOLLRDNORM
                EPOLLRDBAND 
            = 0x080,
            #define EPOLLRDBAND EPOLLRDBAND
                EPOLLWRNORM 
            = 0x100,
            #define EPOLLWRNORM EPOLLWRNORM
                EPOLLWRBAND 
            = 0x200,
            #define EPOLLWRBAND EPOLLWRBAND
                EPOLLMSG 
            = 0x400,
            #define EPOLLMSG EPOLLMSG
                EPOLLERR 
            = 0x008,
            #define EPOLLERR EPOLLERR
                EPOLLHUP 
            = 0x010,
            #define EPOLLHUP EPOLLHUP
                EPOLLRDHUP 
            = 0x2000,
            #define EPOLLRDHUP EPOLLRDHUP
                EPOLLONESHOT 
            = (1 << 30),
            #define EPOLLONESHOT EPOLLONESHOT
                EPOLLET 
            = (1 << 31)
            #define EPOLLET EPOLLET
              };


            /* Valid opcodes ( "op" parameter ) to issue to epoll_ctl().  */
            #define EPOLL_CTL_ADD 1    /* Add a file decriptor to the interface.  */
            #define EPOLL_CTL_DEL 2    /* Remove a file decriptor from the interface.  */
            #define EPOLL_CTL_MOD 3    /* Change file decriptor epoll_event structure.  */


            typedef union epoll_data
            {
              
            void *ptr;
              
            int fd;
              uint32_t u32;
              uint64_t u64;
            } epoll_data_t;

            struct epoll_event
            {
              uint32_t events;    
            /* Epoll events */
              epoll_data_t data;    
            /* User data variable */
            };


            __BEGIN_DECLS

            /* Creates an epoll instance.  Returns an fd for the new instance.
               The "size" parameter is a hint specifying the number of file
               descriptors to be associated with the new instance.  The fd
               returned by epoll_create() should be closed with close().  
            */
            extern int epoll_create (int __size) __THROW;


            /* Manipulate an epoll instance "epfd". Returns 0 in case of success,
               -1 in case of error ( the "errno" variable will contain the
               specific error code ) The "op" parameter is one of the EPOLL_CTL_*
               constants defined above. The "fd" parameter is the target of the
               operation. The "event" parameter describes which events the caller
               is interested in and any associated user data.  
            */
            extern int epoll_ctl (int __epfd, int __op, int __fd,
                          
            struct epoll_event *__event) __THROW;


            /* Wait for events on an epoll instance "epfd". Returns the number of
               triggered events returned in "events" buffer. Or -1 in case of
               error with the "errno" variable set to the specific error code. The
               "events" parameter is a buffer that will contain triggered
               events. The "maxevents" is the maximum number of events to be
               returned ( usually size of "events" ). The "timeout" parameter
               specifies the maximum wait time in milliseconds (-1 == infinite).

               This function is a cancellation point and therefore not marked with
               __THROW.  
            */
            extern int epoll_wait (int __epfd, struct epoll_event *__events,
                           
            int __maxevents, int __timeout);


            /* Same as epoll_wait, but the thread's signal mask is temporarily
               and atomically replaced with the one provided as parameter.

               This function is a cancellation point and therefore not marked with
               __THROW.  
            */
            extern int epoll_pwait (int __epfd, struct epoll_event *__events,
                        
            int __maxevents, int __timeout,
                        __const __sigset_t 
            *__ss);

            __END_DECLS

            #endif /* sys/epoll.h */




            // epoll.cpp : Defines the entry point for the console application.
            //

            #include 
            "stdafx.h"


            #define MAX_EVENTS 10     
            #define PORT 8080     
            //設置socket連接為非阻塞模式     
            void setnonblocking(int sockfd) {    
                
            int opts;    

                opts 
            = fcntl(sockfd, F_GETFL);    
                
            if(opts < 0) {    
                    perror(
            "fcntl(F_GETFL)\n");    
                    exit(
            1);    
                }    
                opts 
            = (opts | O_NONBLOCK);    
                
            if(fcntl(sockfd, F_SETFL, opts) < 0) {    
                    perror(
            "fcntl(F_SETFL)\n");    
                    exit(
            1);    
                }    
            }    

            int main()
            {    
                
            struct epoll_event ev, events[MAX_EVENTS];    
                
            int addrlen, listenfd, conn_sock, nfds, epfd, fd, i, nread, n;    
                
            struct sockaddr_in local, remote;    
                
            char buf[BUFSIZ];    

                
            //創建listen socket     
                if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {    
                    perror(
            "sockfd\n");    
                    exit(
            1);    
                }    
                setnonblocking(listenfd);    
                bzero(
            &local, sizeof(local));    
                local.sin_family 
            = AF_INET;    
                local.sin_addr.s_addr 
            = htonl(INADDR_ANY);;    
                local.sin_port 
            = htons(PORT);    
                
            if( bind(listenfd, (struct sockaddr *&local, sizeof(local)) < 0) {    
                    perror(
            "bind\n");    
                    exit(
            1);    
                }    
                listen(listenfd, 
            20);    
                epfd 
            = epoll_create(MAX_EVENTS);
                pr_debug(
            "listenfd:%d,epfd:%d",listenfd,epfd);
                
            if (epfd == -1) {    
                    perror(
            "epoll_create");    
                    exit(EXIT_FAILURE);    
                }      
                ev.events 
            = EPOLLIN;    
                ev.data.fd 
            = listenfd;    
                
            if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) {    
                    perror(
            "epoll_ctl: listen_sock");    
                    exit(EXIT_FAILURE);    
                }    

                
            for (;;) {
                    
            //nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); 
                    nfds = epoll_wait(epfd, events, MAX_EVENTS, 1000); 

                    pr_debug(
            "nfds:%d",nfds);
                    
            if (nfds == -1) {    
                        perror(
            "epoll_pwait");    
                        exit(EXIT_FAILURE);    
                    }    

                    
            for (i = 0; i < nfds; ++i) 
                    {    
                        fd 
            = events[i].data.fd;    
                        
            if (fd == listenfd)
                        {
                            
            while ((conn_sock = accept(listenfd,(struct sockaddr *&remote, (size_t *)&addrlen)) > 0)     
                            {    
                                setnonblocking(conn_sock);    
                                ev.events 
            = EPOLLIN | EPOLLET;    
                                ev.data.fd 
            = conn_sock;    
                                
            if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1)  
                                {    
                                        perror(
            "epoll_ctl: add");    
                                        exit(EXIT_FAILURE);    
                                }    
                            }    
                            
            if (conn_sock == -1) {    
                                
            if (errno != EAGAIN && errno != ECONNABORTED     
                                    
            && errno != EPROTO && errno != EINTR)     
                                    perror(
            "accept");    
                            }    
                            
            continue;    
                        }      
                        
            if (events[i].events & EPOLLIN)
                        {    
                            n 
            = 0;    
                            
            while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) {    
                                n 
            += nread;    
                            }    
                            
            if (nread == -1 && errno != EAGAIN) {    
                                perror(
            "read error");    
                            }    
                            ev.data.fd 
            = fd;    
                            ev.events 
            = events[i].events | EPOLLOUT;    
                            
            if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1) {    
                                perror(
            "epoll_ctl: mod");    
                            }    
                        }    
                        
            if (events[i].events & EPOLLOUT)
                        {    
                            sprintf(buf, 
            "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\nHello World"11);    
                            
            int nwrite, data_size = strlen(buf);    
                            n 
            = data_size;    
                            
            while (n > 0) {    
                                nwrite 
            = write(fd, buf + data_size - n, n);    
                                
            if (nwrite < n) {    
                                    
            if (nwrite == -1 && errno != EAGAIN) {    
                                        perror(
            "write error");    
                                    }    
                                    
            break;    
                                }    
                                n 
            -= nwrite;    
                            }    
                            close(fd);    
                        }    
                    }    
                }    

                
            return 0;    
            }

            posted on 2014-03-21 16:56 天下 閱讀(816) 評論(0)  編輯 收藏 引用 所屬分類: Linux編程

            <2013年3月>
            242526272812
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            久久婷婷是五月综合色狠狠| 青青草原综合久久| 久久精品国产精品亚洲艾草网美妙| 久久综合88熟人妻| 久久一日本道色综合久久| 少妇精品久久久一区二区三区| 国产精品一区二区久久精品涩爱| 亚洲?V乱码久久精品蜜桃| 欧美成a人片免费看久久| 久久亚洲2019中文字幕| 噜噜噜色噜噜噜久久| 精品国产乱码久久久久软件 | 一本一道久久综合狠狠老| 久久亚洲精品无码VA大香大香| 一极黄色视频久久网站| 亚洲国产精品无码成人片久久| 亚洲精品美女久久777777| 伊人久久无码中文字幕| 久久99精品久久久久久久不卡| 久久久久久免费一区二区三区| 丁香五月综合久久激情| 中文字幕无码久久精品青草| 亚洲va久久久噜噜噜久久狠狠| 国产精品美女久久久久网| 久久人人超碰精品CAOPOREN| 一本色道久久88—综合亚洲精品| 久久婷婷成人综合色综合| 国产精品久久久天天影视香蕉 | 无码人妻久久久一区二区三区 | 奇米综合四色77777久久| 久久99精品国产麻豆宅宅| 一级女性全黄久久生活片免费| 亚洲国产欧美国产综合久久| 欧美伊香蕉久久综合类网站| 久久亚洲日韩看片无码| 欧美精品一区二区精品久久| 久久99久久99精品免视看动漫| 成人精品一区二区久久| 青草国产精品久久久久久| 无码精品久久一区二区三区| 国产精品久久永久免费|