• <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>
            posts - 297,  comments - 15,  trackbacks - 0
            [轉]epoll用法說明(源代碼)


            epoll用到的所有函數都是在 頭文件sys/epoll.h中聲明的,下面簡要說明所用到的數據結構和函數:
            所用到的數據結構
            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 */
                    };
            結構體 epoll_event 被用于注冊所感興趣的事件和回傳所發生待處理的事件,其中epoll_data 聯合體用來保存觸發事件的某個文件描述符相關的數據,例如一個client連接到服務器,服務器通過調用accept函數可以得到于這個client對應 的socket文件描述符,可以把這文件描述符賦給epoll_data的fd字段以便后面的讀寫操作在這個文件描述符上進行。epoll_event 結構體的events字段是表示感興趣的事件和被觸發的事件可能的取值為:EPOLLIN :表示對應的文件描述符可以讀;
            EPOLLOUT:表示對應的文件描述符可以寫;
            EPOLLPRI:表 示對應的文件描述符有緊急的數據可讀(我不太明白是什么意思,可能是類似client關閉  socket連接這樣的事件);
            EPOLLERR:表 示對應的文件描述符發生錯誤;
            EPOLLHUP:表示對應的文件描述符被掛斷;
            EPOLLET:表 示對應的文件描述符有事件發生;
            所用到的函數:
            1、epoll_create函數
                 函數聲明:int epoll_create(int size)
                該函數生成一個epoll專用的文件描述符,其中的參數是指定生成描述符的最大范圍(我覺得這個參數和select函數的第一個參數應該是類似的但是該怎 么設置才好,我也不太清楚)。
            2、epoll_ctl函數
                 函數聲明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
                
            該函數用于控制某個文件描述符上的事 件,可以注冊事件,修改事件,刪除事件。
                參數:epfd:由 epoll_create 生成的epoll專用的文件描述符;
                            op:要進行的操作例如注冊事件,可能的取值EPOLL_CTL_ADD 注冊、EPOLL_CTL_MOD
                                    改、EPOLL_CTL_DEL 刪除
                            fd:關聯的文件描述符;
                            event:指向epoll_event的指針;
                如果調用成功返回0,不成功返回-1
            3、epoll_wait函數
            函數聲明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)

            該函數用于輪詢I/O事件的發生;
            參數:
            epfd:由epoll_create 生成的epoll專用的文件描述符;
            epoll_event:用于回傳代處理事件的數組;
            maxevents:每次能處理的事件數;
            timeout: 等待I/O事件發生的超時值;
            返回發生事件數。
            例子:


             #include <stdio.h>
            #include <stdlib.h>
            #include <errno.h>
            #include <string.h>
            #include <sys/types.h>
            #include <netinet/in.h>
            #include <sys/socket.h>
            #include <sys/wait.h>
            #include <unistd.h>
            #include <arpa/inet.h>
            #include <openssl/ssl.h>
            #include <openssl/err.h>
            #include <fcntl.h>
            #include <sys/epoll.h>
            #include <sys/time.h>
            #include <sys/resource.h>


            #define MAXBUF 1024
            #define MAXEPOLLSIZE 10000

            /*
            setnonblocking - 設置句柄為非阻塞方式
            */
            int setnonblocking(int sockfd)
            {
                if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
                    return -1;
                }
                return 0;
            }

            /*
            handle_message - 處理每個 socket 上的消息收發
            */
            int handle_message(int new_fd)
            {
                char buf[MAXBUF + 1];
                int len;
                /* 開始處理每個新連接上的數據收發 */
                bzero(buf, MAXBUF + 1);
                /* 接收客戶端的消息 */
                len = recv(new_fd, buf, MAXBUF, 0);
                if (len > 0)
                    printf
                        ("%d接收消息成功:'%s',共%d個字節的數據\n",
                         new_fd, buf, len);
                else {
                    if (len < 0)
                        printf
                            ("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n",
                             errno, strerror(errno));
                    close(new_fd);
                    return -1;
                }
                /* 處理每個新連接上的數據收發結束 */
                return len;
            }
            /************ 關于本文檔********************************************
            *filename: epoll-server.c
            *purpose: 演示epoll處理海量socket連接的方法
            *wrote by: zhoulifa(zhoulifa@163.com) 周立發(http://zhoulifa.bokee.com)
            Linux愛好者 Linux知識傳播者 SOHO族 開發者 最擅長C語言
            *date time:2007-01-31 21:00
            *Note: 任何人可以任意復制代碼并運用這些文檔,當然包括你的商業用途
            * 但請遵循GPL
            *Thanks to:Google
            *Hope: 希望越來越多的人貢獻自己的力量,為科學技術發展出力
            * 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!
            *********************************************************************/
            int main(int argc, char **argv)
            {
                int listener, new_fd, kdpfd, nfds, n, ret, curfds;
                socklen_t len;
                struct sockaddr_in my_addr, their_addr;
                unsigned int myport, lisnum;
                struct epoll_event ev;
                struct epoll_event events[MAXEPOLLSIZE];
                struct rlimit rt;

                if (argv[1])
                    myport = atoi(argv[1]);
                else
                    myport = 7838;

                if (argv[2])
                    lisnum = atoi(argv[2]);
                else
                    lisnum = 2;

                /* 設置每個進程允許打開的最大文件數 */
                rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
                if (setrlimit(RLIMIT_NOFILE, &rt) == -1) {
                    perror("setrlimit");
                    exit(1);
                }
                else printf("設置系統資源參數成功!\n");

                /* 開啟 socket 監聽 */
                if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
                    perror("socket");
                    exit(1);
                } else
                    printf("socket 創建成功!\n");

                setnonblocking(listener);

                bzero(&my_addr, sizeof(my_addr));
                my_addr.sin_family = PF_INET;
                my_addr.sin_port = htons(myport);
                if (argv[3])
                    my_addr.sin_addr.s_addr = inet_addr(argv[3]);
                else
                    my_addr.sin_addr.s_addr = INADDR_ANY;

                if (bind
                    (listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
                    == -1) {
                    perror("bind");
                    exit(1);
                } else
                    printf("IP 地址和端口綁定成功\n");

                if (listen(listener, lisnum) == -1) {
                    perror("listen");
                    exit(1);
                } else
                    printf("開啟服務成功!\n");

                /* 創建 epoll 句柄,把監聽 socket 加入到 epoll 集合里 */
                kdpfd = epoll_create(MAXEPOLLSIZE);
                len = sizeof(struct sockaddr_in);
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = listener;
                if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0) {
                    fprintf(stderr, "epoll set insertion error: fd=%d\n", listener);
                    return -1;
                } else
                    printf("監聽 socket 加入 epoll 成功!\n");
                curfds = 1;
                while (1) {
                    /* 等待有事件發生 */
                    nfds = epoll_wait(kdpfd, events, curfds, -1);
                    if (nfds == -1) {
                        perror("epoll_wait");
                        break;
                    }
                    /* 處理所有事件 */
                    for (n = 0; n < nfds; ++n) {
                        if (events[n].data.fd == listener) {
                            new_fd = accept(listener, (struct sockaddr *) &their_addr,
                                            &len);
                            if (new_fd < 0) {
                                perror("accept");
                                continue;
                            } else
                                printf("有連接來自于: %d:%d, 分配的 socket 為:%d\n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);

                            setnonblocking(new_fd);
                            ev.events = EPOLLIN | EPOLLET;
                            ev.data.fd = new_fd;
                            if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0) {
                                fprintf(stderr, "把 socket '%d' 加入 epoll 失敗!%s\n",
                                        new_fd, strerror(errno));
                                return -1;
                            }
                            curfds++;
                        } else {
                            ret = handle_message(events[n].data.fd);
                            if (ret < 1 && errno != 11) {
                                epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,
                                          &ev);
                                curfds--;
                            }
                        }
                    }
                }
                close(listener);
                return 0;
            }

            編 譯此程序用命令:
            gcc -Wall epoll-server.c -o server

            運行此程序需要具有管理員權限!

            sudo ./server 7838 1

            通過測試這一個服務器可能同時處理10000 -3 = 9997 個連接!

            如果這是 一個在線服務系統,那么它可以支持9997人同時在線,比如游戲、聊天等。
             原文地址 http://blog.chinaunix.net/u/8818/showart_440623.html
            posted on 2010-05-06 12:03 chatler 閱讀(668) 評論(0)  編輯 收藏 引用 所屬分類: Socket
            <2025年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(10)

            隨筆分類(307)

            隨筆檔案(297)

            algorithm

            Books_Free_Online

            C++

            database

            Linux

            Linux shell

            linux socket

            misce

            • cloudward
            • 感覺這個博客還是不錯,雖然做的東西和我不大相關,覺得看看還是有好處的

            network

            OSS

            • Google Android
            • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
            • os161 file list

            overall

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            久久丫忘忧草产品| 精品久久一区二区| 欧美噜噜久久久XXX| 久久久久久九九99精品| 色综合久久综精品| 久久精品成人欧美大片| 996久久国产精品线观看| 亚洲七七久久精品中文国产| 久久婷婷五月综合97色一本一本| 99久久精品无码一区二区毛片| 久久午夜福利无码1000合集| 久久96国产精品久久久| 久久精品久久久久观看99水蜜桃 | 69SEX久久精品国产麻豆| 国产精品午夜久久| 成人国内精品久久久久一区| 精品久久久久久久久免费影院| 国产99久久久国产精免费| 国产精品久久久久久| 久久天天躁狠狠躁夜夜网站| 人妻丰满?V无码久久不卡| 久久夜色tv网站| 国产一区二区三区久久| 一本色道久久综合亚洲精品| 亚洲国产天堂久久久久久| 欧美久久亚洲精品| 爱做久久久久久| 国产精品久久久天天影视香蕉| 91精品国产高清91久久久久久| 久久99亚洲网美利坚合众国| 一本久久a久久精品vr综合| 久久久久亚洲av成人网人人软件| 亚洲七七久久精品中文国产 | 国产成人久久精品激情 | 综合久久一区二区三区 | 国产精品女同久久久久电影院| 久久精品国产色蜜蜜麻豆| 伊人久久大香线蕉亚洲五月天| 漂亮人妻被中出中文字幕久久 | 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 精品久久久无码人妻中文字幕|