1. 程式人生 > >epoll用法說明,ET模式下的邊緣觸發處理同時多事件

epoll用法說明,ET模式下的邊緣觸發處理同時多事件

#include <deque>
#include 
<map>
#include 
<vector>
#include 
<pthread.h>
#include 
<semaphore.h>
#include 
<time.h>
#include 
<sys/time.h>
#include 
<sys/shm.h>
#include 
<errno.h>
#include 
<sys/types.h>
#include 
<fcntl.h>
#include 
<
stdio.h>

#include 
<string>
#include 
<cstdio>
#include 
<unistd.h>
#include 
<signal.h>
#include 
<sys/types.h>
#include 
<sys/stat.h>

#include 
<cstdlib>
#include 
<cctype>
#include 
<sstream>
#include 
<utility>
#include 
<stdexcept
>

#include 
<sys/socket.h> 
#include 
<sys/epoll.h> 
#include 
<netinet/in.h> 
#include 
<arpa/inet.h> 
#include 
<iostream>
#include 
<signal.h>

usingnamespace std;

#pragma pack(
1)

//管道訊息結構
struct pipemsg {
    
int op;
    
int fd;
    unsigned 
int ip;
    unsigned 
short port;
}
;

//地址埠結構
struct ipport {
    unsigned 
int ip;
    unsigned 
short port;
    
booloperator< (const ipport rhs) const{return (ip < rhs.ip || (ip == rhs.ip && port < rhs.port));}
    
booloperator== (const ipport rhs) const{return (ip == rhs.ip && port == rhs.port);}
}
;

//對應於對方地址埠的連線資訊
struct peerinfo {
    
int fd;                    //對應連線控制代碼
    unsigned int contime;    //最後連線時間
    unsigned int rcvtime;    //收到資料時間
    unsigned int rcvbyte;    //收到位元組個數
    unsigned int sndtime;    //傳送資料時間
    unsigned int sndbyte;    //傳送位元組個數
}
;

//連線結構
struct conninfo {
    
int rfd;                                    //管道讀端
int wfd;                                    //管道寫端
    map<struct ipport, struct peerinfo> peer;    //對方資訊
}
;

#pragma pack()

//全域性執行標誌
bool g_bRun;

//全域性連線資訊
struct conninfo g_ConnInfo;

void setnonblocking(int sock) 
{     
    
int opts;     
    opts 
= fcntl(sock,F_GETFL);     
    
if (opts <0)     
    
{         
        perror(
"fcntl(sock,GETFL)");         
        exit(
1);     
    }
     
    opts 
= opts|O_NONBLOCK;     
    
if (fcntl(sock, F_SETFL, opts) <0)     
    
{         
        perror(
"fcntl(sock,SETFL,opts)");         
        exit(
1);     
    }
  
}


void setreuseaddr(int sock)
{
    
int opt;
    opt 
=1;    
    
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(&opt)) <0)     
    
{         
        perror(
"setsockopt");         
        exit(
1);     
    }
  
}


staticvoid sig_pro(int signum)
{
    cout 
<<"sig_pro, recv signal:"<< signum << endl;
    
    
if (signum == SIGQUIT)
    
{
        g_bRun 
=false;
    }

}


//接收連線執行緒
void* AcceptThread(void*arg)
{
    cout 
<<"AcceptThread, enter"<< endl;
    
    
int ret;        //臨時變數,存放返回值
int epfd;        //監聽用的epoll
int listenfd;   //監聽socket
int connfd;        //接收到的連線socket臨時變數
int i;            //臨時變數,輪詢陣列用
int nfds;        //臨時變數,有多少個socket有事件
     
    
struct epoll_event ev;                     //事件臨時變數
constint MAXEVENTS =1024;                //最大事件數
struct epoll_event events[MAXEVENTS];    //監聽事件陣列
    socklen_t clilen;                         //宣告epoll_event結構體的變數,ev用於註冊事件,陣列用於回傳要處理的事件 
struct sockaddr_in cliaddr;     
    
struct sockaddr_in svraddr;
    
    unsigned 
short uListenPort =5000;
    
int iBacklogSize =5;
    
int iBackStoreSize =1024;
    
    
struct pipemsg msg;                        //訊息佇列資料
    
    
//建立epoll,對2.6.8以後的版本,其引數無效,只要大於0的數值就行,核心自己動態分配
    epfd = epoll_create(iBackStoreSize);
    
if (epfd <0)
    
{
        cout 
<<"AcceptThread, epoll_create fail:"<< epfd <<",errno:"<< errno << endl;
        
        
return NULL;
    }

    
    
//建立監聽socket
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    
if (listenfd <0)
    
{
        cout 
<<"AcceptThread, socket fail:"<< epfd <<",errno:"<< errno << endl;
        
        close(epfd);
        
        
return NULL;
    }

       
    
//把監聽socket設定為非阻塞方式     
    setnonblocking(listenfd);
    
//設定監聽socket為埠重用 
    setreuseaddr(listenfd);
      
    
//設定與要處理的事件相關的檔案描述符     
    ev.data.fd = listenfd;     
    
//設定要處理的事件型別     
    ev.events = EPOLLIN|EPOLLET;        
    
//註冊epoll事件   
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
    
if (ret !=0)
    
{
        cout 
<<"AcceptThread, epoll_ctl fail:"<< ret <<",errno:"<< errno << endl;
        
        close(listenfd);
        close(epfd);
        
        
return NULL;
    }
   
 
    bzero(
&svraddr, sizeof(svraddr));     
    svraddr.sin_family 
= AF_INET;     
    svraddr.sin_addr.s_addr 
= htonl(INADDR_ANY);   
    svraddr.sin_port
=htons(uListenPort);     
    bind(listenfd,(sockaddr 
*)&svraddr, sizeof(svraddr));
    
//監聽,準備接收連線   
    ret = listen(listenfd, iBacklogSize);
    
if (ret !=0)
    
{
        cout 
<<"AcceptThread, listen fail:"<< ret <<",errno:"<< errno << endl;
        
        close(listenfd);
        close(epfd);
        
        
return NULL;
    }
   
    
    
while (g_bRun)
    
{
        
//等待epoll事件的發生,如果當前有訊號的控制代碼數大於輸出事件陣列的最大大小,超過部分會在下次epoll_wait時輸出,事件不會丟        
        nfds = epoll_wait(epfd, events, MAXEVENTS, 500);
        
        
//處理所發生的所有事件             
for (i =0; i < nfds && g_bRun; ++i)         
        
{
            
if (events[i].data.fd == listenfd)        //是本監聽socket上的事件   
{
                cout 
<<"AcceptThread, events:"<< events[i].events <<",errno:"<< errno << endl;
                
                
if (events[i].events&EPOLLIN)    //有連線到來
{
                    
do

相關推薦

epoll用法說明ET模式邊緣觸發處理同時事件

#include <deque> #include <map> #include <vector> #include <pthread.h> #include <semaphore.h> #in

epoll學習筆記(ET模式事件觸發原理和資料收發存在的問題)

這篇文章所講的例子和情況可以結合《epoll的LT模式和ET模式 》這篇看。 epoll有兩種模式,Edge Triggered(簡稱ET) 和 Level Triggered(簡稱LT).在採用這兩種模式時要注意的是,如果採用ET模式,那麼僅當狀態發生變化時才會通知,而採

Epoll在LT和ET模式的讀寫方式和區別

LT模式:epoll就是一個快速版poll,可讀可寫就緒條件和傳統poll一致 ET模式:為了避免Starvation,建議           1)檔案描述符設定為非阻塞           2)只在read或write返回EAGAIN後,才能呼叫下一次epoll

epoll在LT和ET模式的讀寫方式

在一個非阻塞的socket上呼叫read/write函式, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 從字面上看, 意思是: * EAGAIN: 再試一次 * EWOULDBLOCK: 如果這是一個阻塞socket

epoll反應堆及ET模式的EPOLLOUT學習總結

學習epoll反應堆發現網上的epoll反應堆都是同一份程式碼框架… 自己理解、梳理一遍,思路在註釋裡 #include <stdlib.h> #include <stdio.h> #include <stdio.h>

Epoll-ET模式非阻塞讀寫之Buffer的封裝

先說說Epoll的ET模式 epoll預設的模式是LT,要說ET不得不提到LT,LT與ET的區別可以用一句話概括: LT模式下只要socket處於可讀狀態(新增EPOLLIN事件時)或可寫

EPOLLET模式會被觸發次麼?

前幾天和同學一起討論EPOLLONESHOT的作用,它的功能是這樣的: 對於註冊了EPOLLONESHOT事件的檔案描述符,作業系統最多觸發其上註冊的包括可讀,可寫,錯誤中的一個,且只觸發一次 剛一看感覺EPOLLONESHOT咋麼就是ET模式相對於LT模

RedisTemplate執行lua指令碼叢集模式報錯解決

redis叢集配置: 在使用spring的RedisTemplate執行lua指令碼時,報錯EvalSha is not supported in cluster environment,不支援cluster。 程式碼: @Test public

Vue開發及上線過程中遇到的坑(axios跨域history模式空白頁問題)

最近公司在用vue開發一個網站,在這過程中,遇到了一些需要注意的點,在此先列出來,防止下次再次踩坑 1.在開發環境下,使用axios進行資料互動時,如果遇到跨域問題的話,可以在如下圖 Config檔案下的index.js 設定proxy代理 你可以新建一個專門放介面

Linux系統忘記root密碼緊急模式更改密碼

測試 http passwd inf 界面 str 下界 eboot -s linux忘記密碼命令概括:   1.開機按e,rd.break,ctrl+x;   2.mount -o remount,rw /sysroot   3.chroot /sysroot

MVVM模式 所有控制元件共享同一事件 以TextBox只能輸入數字鍵和回車鍵為例子

一:首先對MvvmLight裡的ViewModel進行封裝    封裝完畢後讓ViewModel繼承DialogViewModel  public class DialogViewModel : ViewModelBase     {         public voi

div和內部的a標籤都有click事件點選a不觸發div的click事件

  <div> <a></a> </div> $("a").click(function(){ event.stopPropagation(); }) 詳情見: https://blog.csdn.net/u0

VM虛擬機網絡在Bridge模式本機不能連接SSH問題的解決

機器 checksum 模式 load iptable off pos disable ssh設置 今天遇到了一個很奇怪的問題。 VM虛擬機網絡連接原先在NAT模式下,本機通過SSH訪問沒有任何問題,但切換到Bridge模式後,SSH死活都連接不上。以為是自己SSH設

改進Vim體驗:在插入模式移動光標我不要用方向鍵!alt快捷鍵使用技巧!

targe 判斷 映射 tar 什麽 nbsp .vimrc 一次 time 改進Vim體驗:在插入模式下移動光標,我不要用方向鍵!alt快捷鍵使用技巧! 大家都知道,我們在插入模式下編輯代碼的時候 若想寫完這一部分後,移動到鄰近的一部分,如下一個單詞的後面,是很復雜的

SQL Server SQL性能優化之--數據庫在“簡單”參數化模式自動參數化SQL帶來的問題

參考 itl stat 數據行 img tro while 第一次 line 數據庫參數化的模式 數據庫的參數化有兩種方式,簡單(simple)和強制(forced),默認的參數化默認是“簡單”,簡單模式下,如果每次發過來的SQL,除非完全一樣

高性能網絡服務器編程:為什麽linuxepoll是最好Netty要比NIO.2好?

系統 工作效率 lee socket 為我 handler 10g 函數 適合 基本的IO編程過程(包括網絡IO和文件IO)是,打開文件描述符(windows是handler,java是stream或channel),多路捕獲(Multiplexe,即select和poll

epoll的水平觸發邊緣觸發以及邊緣觸發為什麽要使用非阻塞IO

alt 開啟 本機 另一個 trigger stdio.h 什麽 我們 水平 轉自:http://www.cnblogs.com/yuuyuu/p/5103744.html 一.基本概念

flask的debug模式網頁輸入pin碼進行調試

lsp png 資源文件 post 上下文 .com highlight lai target 網站後端Python+Flask .FLASK調試模式之開啟DEBUG與PIN使用? 自動加載: # 方式一 1 2 if __nam

grub legacy練習 之破壞MBR中的Bootloader而後在救援模式修復之

修復centos啟動1. 用dd命令對grub進行破壞2.然後重啟,鏡像位置選擇正確後,會出現下圖界面,點擊Rescue救援模式進行救援;3.跳過網卡設置,直接選擇Continue選項進行救援;4.點擊OK5.點擊OK5.然後出現下邊的命令行,輸入命令之後,如圖(quit錯誤,是exit)6.出現如圖所示開

安裝glibc錯誤鏈接導致系統崩潰u盤啟動緊急救援模式修復系統。

-bash 回車 符號 根目錄 image ali 崩潰 mbo config Sln 命令 創建動態符號鏈接 用法 sln source dest 故障案例:一個誤操作 導致了一個不小的故障,輸入所有命令都無效,直接系統無法啟動。 故障描述 sln /