• <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
            [轉(zhuǎn)]epoll用法說明(源代碼)


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

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


             #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 - 設(shè)置句柄為非阻塞方式
            */
            int setnonblocking(int sockfd)
            {
                if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
                    return -1;
                }
                return 0;
            }

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

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

                /* 開啟 socket 監(jiān)聽 */
                if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
                    perror("socket");
                    exit(1);
                } else
                    printf("socket 創(chuàng)建成功!\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("開啟服務(wù)成功!\n");

                /* 創(chuàng)建 epoll 句柄,把監(jiān)聽 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("監(jiān)聽 socket 加入 epoll 成功!\n");
                curfds = 1;
                while (1) {
                    /* 等待有事件發(fā)生 */
                    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

            運(yùn)行此程序需要具有管理員權(quán)限!

            sudo ./server 7838 1

            通過測試這一個(gè)服務(wù)器可能同時(shí)處理10000 -3 = 9997 個(gè)連接!

            如果這是 一個(gè)在線服務(wù)系統(tǒng),那么它可以支持9997人同時(shí)在線,比如游戲、聊天等。
             原文地址 http://blog.chinaunix.net/u/8818/showart_440623.html
            posted on 2010-05-06 12:03 chatler 閱讀(650) 評論(0)  編輯 收藏 引用 所屬分類: Socket
            <2009年12月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(10)

            隨筆分類(307)

            隨筆檔案(297)

            algorithm

            Books_Free_Online

            C++

            database

            Linux

            Linux shell

            linux socket

            misce

            • cloudward
            • 感覺這個(gè)博客還是不錯(cuò),雖然做的東西和我不大相關(guān),覺得看看還是有好處的

            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

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            久久AV高清无码| 999久久久免费精品国产| 国产成人精品久久亚洲| 久久精品亚洲欧美日韩久久| 久久天天躁狠狠躁夜夜2020老熟妇 | 国产—久久香蕉国产线看观看 | 嫩草伊人久久精品少妇AV| 久久久久久久久久久久中文字幕| 精品久久久久久国产| 伊人色综合久久天天网| 国产精品一久久香蕉产线看| 天天做夜夜做久久做狠狠| 国产亚洲精品美女久久久| 久久强奷乱码老熟女网站| 精品久久久久香蕉网| 中文精品99久久国产| 国产成人无码精品久久久免费 | 亚洲国产成人精品无码久久久久久综合| 伊人久久大香线蕉成人| 久久福利青草精品资源站免费| 久久精品中文字幕有码| 精品久久久久久无码专区不卡| 久久精品国产亚洲精品| 国内精品伊人久久久久AV影院| 免费精品久久天干天干| 国产精品成人99久久久久 | 久久久久亚洲AV综合波多野结衣 | 国产精品久久影院| 狠狠色婷婷久久综合频道日韩| 久久久精品国产Sm最大网站| 国产精品久久久天天影视| 久久66热人妻偷产精品9| 久久久久亚洲AV无码观看| 亚洲国产精品一区二区三区久久| 国产A级毛片久久久精品毛片| 国内精品人妻无码久久久影院导航| 久久综合久久综合久久综合| 久久99精品久久久久久动态图| 亚洲国产精品成人久久| 久久国语露脸国产精品电影| 亚洲欧美日韩久久精品第一区|