青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天下

記錄修行的印記

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 天下 閱讀(827) 評論(0)  編輯 收藏 引用 所屬分類: Linux編程

<2013年8月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

導航

統計

常用鏈接

留言簿(4)

隨筆分類(378)

隨筆檔案(329)

鏈接

最新隨筆

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美伦理a级免费电影| 一区二区欧美亚洲| 欧美金8天国| 免费观看不卡av| 男人的天堂亚洲| 欧美黄色免费| 欧美日韩一区二区三区在线 | 久久午夜电影| 久久网站热最新地址| 久久免费高清| 欧美大色视频| 国产精品观看| 国产亚洲欧美一区在线观看| 激情丁香综合| 一片黄亚洲嫩模| 欧美在线不卡视频| 男男成人高潮片免费网站| 亚洲二区在线视频| 91久久久久久久久久久久久| 在线亚洲免费| 久久精品视频在线看| 欧美国产精品一区| 国产日产亚洲精品| 亚洲黄色影片| 欧美一级在线视频| 欧美激情一二三区| 亚洲免费网址| 欧美日韩成人一区| 一区二区三区在线视频播放| 久久黄金**| 奶水喷射视频一区| 亚洲视频大全| 欧美国产三级| 精品99一区二区| 亚洲欧美在线一区| 亚洲国产精品热久久| 亚洲伊人一本大道中文字幕| 免费av成人在线| 国产日韩欧美在线播放不卡| 亚洲靠逼com| 免费看成人av| 久久精品视频免费| 国产精品久久二区| 亚洲国产精品久久久久秋霞影院 | 久久久久高清| 国产精品久久久久影院色老大 | 国产亚洲精品v| 亚洲视屏一区| 亚洲人永久免费| 久久婷婷久久一区二区三区| 国产精品视频大全| 亚洲视频一二区| 亚洲精品欧美| 欧美激情影音先锋| 亚洲精品在线电影| 亚洲国产高清自拍| 欧美 日韩 国产精品免费观看| 国产一区三区三区| 久久久久久久久久久久久女国产乱 | 99视频精品| 欧美电影在线观看完整版| 久久久久久久激情视频| 狠狠干狠狠久久| 久色成人在线| 久久亚洲不卡| 亚洲黄色小视频| 亚洲第一精品电影| 欧美电影在线免费观看网站| 亚洲精品免费一二三区| 亚洲欧洲日产国产网站| 欧美激情视频在线播放| 一本色道久久综合亚洲精品小说| 亚洲精品视频在线看| 欧美日韩免费高清| 亚洲一区二区三区精品视频| 亚洲天堂成人在线观看| 国产精品亚洲欧美| 久久婷婷一区| 欧美+亚洲+精品+三区| 中文在线不卡| 亚洲欧美一区二区三区极速播放| 国产视频不卡| 亚洲第一中文字幕在线观看| 欧美日韩一区二区免费在线观看| 午夜在线视频一区二区区别| 欧美在线视频在线播放完整版免费观看| 国产一区久久久| 亚洲激情国产| 午夜精品999| 久久精品色图| 一区二区欧美日韩| 亚洲在线不卡| 在线播放一区| 亚洲蜜桃精久久久久久久| 国产精品乱人伦中文| 另类人畜视频在线| 欧美日韩视频一区二区| 久久久久综合一区二区三区| 欧美国产欧美综合 | 欧美刺激午夜性久久久久久久| 蜜桃av一区| 午夜日韩激情| 欧美成人高清视频| 亚洲欧美日韩一区在线观看| 久久久久久久一区二区| 国产精品99久久不卡二区| 久久成人精品一区二区三区| 一区二区三区高清视频在线观看| 午夜在线电影亚洲一区| 亚洲精品久久久久久一区二区 | 亚洲一区二区在线视频| 久久精品国产69国产精品亚洲 | 极品尤物一区二区三区| aⅴ色国产欧美| 亚洲国产精品一区二区尤物区 | 久久久综合激的五月天| 正在播放欧美视频| 老鸭窝毛片一区二区三区| 亚洲男女自偷自拍| 欧美电影免费观看大全| 久久久久亚洲综合| 国产三级欧美三级| 日韩亚洲欧美中文三级| 亚洲人成绝费网站色www| 久久久久久91香蕉国产| 久久国产主播精品| 国产精品日韩在线观看| 一区二区三区黄色| 亚洲手机在线| 欧美三级欧美一级| 99精品国产在热久久| 99国产精品99久久久久久粉嫩| 牛人盗摄一区二区三区视频| 欧美成人免费小视频| 亚洲高清123| 久久一综合视频| 欧美成人国产va精品日本一级| 在线看欧美日韩| 麻豆成人小视频| 亚洲国产合集| 亚洲图中文字幕| 国产精品免费网站在线观看| 亚洲性xxxx| 久久久久久久综合日本| 黄色成人在线免费| 欧美一级片久久久久久久| 国产精品videosex极品| 麻豆精品视频| 亚洲欧洲精品天堂一级| 欧美大香线蕉线伊人久久国产精品| 嫩草成人www欧美| 亚洲精品国精品久久99热| 欧美日韩成人综合在线一区二区| 亚洲日本视频| 性欧美18~19sex高清播放| 国产精品日韩精品| 久久精彩视频| 亚洲精品一区在线观看香蕉| 亚洲欧美成人网| 国产综合久久久久久| 美女免费视频一区| 99精品黄色片免费大全| 久久手机精品视频| 日韩一区二区精品视频| 国产精品一区二区黑丝| 久久夜色精品国产欧美乱| 亚洲精品国产精品久久清纯直播| 亚洲欧美日韩天堂| 在线高清一区| 欧美日韩午夜视频在线观看| 午夜精品视频在线观看| 欧美激情第二页| 欧美伊人久久大香线蕉综合69| 亚洲国产一区在线| 国产精品视频1区| 欧美精品久久久久久久免费观看| 亚洲综合色激情五月| 欧美国产日韩一二三区| 性xx色xx综合久久久xx| 亚洲理论电影网| 国产主播一区二区| 欧美日韩大陆在线| 久久手机免费观看| 亚洲在线1234| 一本一本大道香蕉久在线精品| 另类图片国产| 久久激情五月丁香伊人| 一本色道久久88精品综合| 激情成人在线视频| 欧美日韩一区二区三区在线观看免| 久久久综合精品| 午夜视频在线观看一区二区三区| 亚洲肉体裸体xxxx137| 免费久久99精品国产自| 久久精品亚洲一区二区| 午夜精彩视频在线观看不卡 | 亚洲一区二区三区乱码aⅴ| 亚洲大胆视频| 美女国产一区| 久久精品视频在线|