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

天下

記錄修行的印記

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>
            国产精品免费看片| 久久久综合激的五月天| 亚洲美女视频网| 欧美亚洲免费高清在线观看| 欧美国产激情| 久久av一区二区| 国产伦精品一区二区三区四区免费 | 久久九九免费视频| 一区二区三区国产在线| 欧美激情一区二区在线| 一区二区动漫| 亚洲综合精品自拍| 在线成人小视频| 亚洲精品视频在线看| 国产精品久久97| 免费在线亚洲| 国产精品―色哟哟| 欧美ed2k| 国产精品看片资源| 免费91麻豆精品国产自产在线观看| 久久久午夜精品| 亚洲欧美激情视频| 麻豆精品在线观看| 亚洲资源在线观看| 噜噜噜躁狠狠躁狠狠精品视频| 一区二区三区国产精华| 欧美一区永久视频免费观看| 亚洲国产日韩一级| 亚洲欧美一区二区原创| av不卡在线| 欧美国产国产综合| 欧美.www| 亚洲精品美女91| 久久久综合网| 久久久久九九视频| 国产精品一区二区在线| 在线亚洲一区观看| 日韩亚洲一区二区| 欧美另类人妖| 在线亚洲成人| 国产精品久久777777毛茸茸| 亚洲欧洲日产国产综合网| 欧美视频一区二区三区| 亚洲欧洲精品一区二区精品久久久| 国产亚洲第一区| 亚洲免费在线精品一区| 久久激情视频免费观看| 国产小视频国产精品| 亚洲欧美激情视频在线观看一区二区三区| 99精品国产在热久久| 一区二区三区自拍| 久久米奇亚洲| 欧美www在线| 一本不卡影院| 国产午夜精品一区二区三区视频| 欧美一区二区三区婷婷月色| 久久在线播放| 亚洲午夜视频在线| 国产日韩一区| 欧美激情视频一区二区三区不卡| 亚洲美女淫视频| 欧美一区91| 99精品视频免费观看| 国产欧美精品在线播放| 美女国产一区| 欧美一级成年大片在线观看| 欧美 日韩 国产一区二区在线视频| 一本色道久久88综合日韩精品| 国产精品亚洲一区二区三区在线| 亚洲视频中文| 欧美顶级大胆免费视频| 亚洲淫片在线视频| 最新国产精品拍自在线播放| 久久国产精品99精品国产| 日韩亚洲欧美高清| 亚洲精品自在在线观看| 亚洲第一天堂av| 国际精品欧美精品| 一本大道av伊人久久综合| 久久在线91| 久久aⅴ乱码一区二区三区| 一本一本久久| 中文精品视频| 午夜视频在线观看一区二区三区| 亚洲精品一区二| 亚洲欧洲日产国产网站| 亚洲欧洲一区二区三区在线观看| 国产欧美精品xxxx另类| 国产揄拍国内精品对白| 狠狠久久婷婷| 91久久黄色| 国产精品99久久久久久白浆小说 | 一区二区久久| 亚洲在线成人| 久久综合给合久久狠狠色| 欧美高清一区| 国产精自产拍久久久久久蜜| 国产日韩欧美精品综合| 国产综合亚洲精品一区二| 亚洲片区在线| 久久精品一本久久99精品| 亚洲国产精品va在看黑人| 91久久精品美女| 欧美日韩三级| 久久精品国产亚洲精品| 欧美福利一区二区| 亚洲最新在线视频| 久久夜色精品国产噜噜av| 欧美日韩一区二区高清| 亚洲国产精品精华液网站| 亚洲欧美日韩在线播放| 欧美国产一区二区三区激情无套| 亚洲黄色免费电影| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 亚洲黄色尤物视频| 久久久久久久久久久成人| 欧美三级日本三级少妇99| 亚洲国产精品t66y| 麻豆精品视频在线| 久久久蜜桃一区二区人| 国产精品永久免费视频| 亚洲欧美日韩国产一区二区| 亚洲麻豆视频| 国产精品久久久久久久久免费樱桃 | 亚洲永久免费av| 在线一区观看| 国产精品呻吟| 欧美91福利在线观看| 牛夜精品久久久久久久99黑人 | 国产精品日韩精品| 亚洲伦理一区| 久久国产日本精品| 亚洲欧美视频在线观看| 国产伦精品一区二区三区免费迷 | 国产精品美女久久久久aⅴ国产馆| 亚洲黄色成人久久久| 亚洲激情在线激情| 欧美日韩播放| 久久精品国产69国产精品亚洲| 亚洲一区在线直播| 亚洲国产1区| 亚洲毛片播放| 一区二区三区**美女毛片| 国产精品久久网站| 免费在线视频一区| 国产精品欧美在线| 欧美va亚洲va国产综合| 国产欧美精品一区二区三区介绍| 免费在线日韩av| 国产精品成人观看视频免费| 久久精品二区三区| 国产精品扒开腿爽爽爽视频| 久久一本综合频道| 国产欧美视频一区二区三区| 亚洲美女区一区| 最近中文字幕mv在线一区二区三区四区| 国产精品欧美久久| 欧美亚洲一区三区| 欧美日韩国产美| 亚洲黄色高清| 一级日韩一区在线观看| 女仆av观看一区| 欧美激情精品久久久久久黑人| 国产日韩视频| 久久久人成影片一区二区三区 | 久久伊人一区二区| 欧美中文字幕久久| 国产毛片精品国产一区二区三区| 中文高清一区| 欧美一区二区三区免费观看视频| 国产精品成人免费| 午夜在线播放视频欧美| 久久久久久久久久久久久9999| 国产目拍亚洲精品99久久精品| 亚洲一区二区三区中文字幕| 久久精品国亚洲| 影音先锋国产精品| 欧美精品在欧美一区二区少妇| 亚洲免费观看高清完整版在线观看| 亚洲天堂网在线观看| 国产在线国偷精品产拍免费yy| 国产日韩欧美在线视频观看| 亚洲一区二区三区激情| 久久久美女艺术照精彩视频福利播放| 国产日产欧美精品| 欧美91视频| 亚洲欧美区自拍先锋| 亚洲国产经典视频| 亚洲欧美视频一区二区三区| 精久久久久久| 国产精品捆绑调教| 欧美xx69| 中日韩高清电影网| 国产一区二区黄| 欧美日韩精品国产| 久久深夜福利| 欧美一级久久久| 中文国产一区| 日韩视频在线一区二区| 免费一级欧美片在线观看|