1. 程式人生 > >linux epoll監聽套接字例項

linux epoll監聽套接字例項

linux epoll機制用於IO多路複用,能夠同時監聽多個接字,使用起來比較簡單。

相關介面:

       #include <sys/epoll.h>

       int epoll_create(int size);
       int epoll_create1(int flags);	//建立epoll例項
       
       int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);    //新增、刪除或修改epoll監聽描述符
       
       int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);//監聽事件發生

其中epoll_ctl引數op有如下選項:分別對應新增、刪除、修改

EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL
             //結構體,在新增到epoll中去的時候可以傳遞引數,引數可以是指標
           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中,每當套接字上有讀事件發生的時候,就可以進行處理。

/*
 *  Description : linux IO多路複用epoll例項
 *  Date        :20180605
 *  Author      :mason
 *  Mail        : [email protected]
 *
 */

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define BUFFER_SIZE 512
#define log(fmt, arg...) printf("[udptest] %s:%d "fmt, __FUNCTION__, __LINE__, ##arg)

void main(){
    int fd1, fd2, efd, fds, i, fd;
    int ret, addr_len;
    struct epoll_event g_event;  // epoll事件
    struct epoll_event *epoll_events_ptr; 
    char buffer[BUFFER_SIZE] = {0};
    struct sockaddr_in addr1, addr2;

    // 建立套接字1
    fd1 = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd1 == -1) {
        log("create socket fail \r\n");
        return ;
    }  
    
    // 建立套接字2   
    fd2 = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd2 == -1) {
        log("create socket fail \r\n");
        close(fd1);
        return ;
    }   

    // 設定監聽地址,不同套接字監聽不同的地址
    addr1.sin_family = AF_INET;
    addr1.sin_addr.s_addr = INADDR_ANY; 
    addr1.sin_port = htons(3500);

    addr2.sin_family = AF_INET;
    addr2.sin_addr.s_addr = INADDR_ANY; 
    addr2.sin_port = htons(3501);
    
    addr_len = sizeof(struct sockaddr_in);
    // 套接字繫結地址
    if (0 != bind(fd1, (struct sockaddr *)&addr1, sizeof(struct sockaddr_in))) {
        log("bind local listening addr fail,errno : %d \r\n", errno);
        goto err;
    }

    if (0 != bind(fd2, (struct sockaddr *)&addr2, sizeof(struct sockaddr_in))) {
        log("bind local listening addr fail,errno : %d \r\n", errno);
        goto err;
    }

    //建立epoll例項
    efd = epoll_create1(0);
    if (efd == -1) {
        log("create epoll fail \r\n");
        goto err;

    }
    log("create epoll instance success \r\n");
    
    epoll_events_ptr = (struct epoll_event *)calloc(2, sizeof(struct epoll_event));
    if (epoll_events_ptr == NULL) {
        log("calloc fail \r\n");
        goto err;
    }

    //新增套接字到epoll中,並監控讀事件
    //注意這裡傳給epoll的引數中可以是指標
    g_event.data.fd = fd1; 
    g_event.events = EPOLLIN;
    epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &g_event);          
    
    g_event.data.fd = fd2; 
    g_event.events = EPOLLIN;
    epoll_ctl(efd, EPOLL_CTL_ADD, fd2, &g_event);  

    //監聽epoll事件
    while(1) {
        log("Starting waiting epoll event \n");
        fds = epoll_wait(efd, epoll_events_ptr, 2, -1); //阻塞
        for (i = 0; i<fds; i++)
        {    
            fd = epoll_events_ptr[i].data.fd;
            if (epoll_events_ptr[i].events & EPOLLIN)
            {   
                ret = read(fd, buffer, BUFFER_SIZE);
                if(ret != -1)
                    log("recv msg : %s \n", buffer);
                    
            }     
            memset(buffer, 0, BUFFER_SIZE);
        }        
    }   

    
err:
    close(fd1);
    close(fd2);
    if(epoll_events_ptr) 
        free(epoll_events_ptr);

    return ;

}

測試結果:

有一點值得注意的是,我在測試用例中當收到epoll事件的時候直接進行了讀取操作,實際應用中這一步可能會阻塞,更好的做法是收到事件傳送訊息到相關的執行緒或者是訊息佇列中,由它們來進行業務處理,epoll只負責通知,這樣能夠提高處理速度。

程式碼可以在gihub上克隆:

[email protected]:FuYuanDe/epoll.git

參考資料:

http://www.man7.org/linux/man-pages/man7/epoll.7.html

相關推薦

linux epoll例項

linux epoll機制用於IO多路複用,能夠同時監聽多個接字,使用起來比較簡單。相關介面: #include <sys/epoll.h> int epoll_create(int size); int epoll_cr

epoll的觸發模式

我們知道epoll有兩種觸發模式:水平觸發(LT)和邊緣觸發(ET) LT模式 若資料可讀,epoll返回可讀事件 若開發者沒有把資料完全讀完,epoll會不斷通知資料可讀,直到資料全部被讀取。 若socket可寫,epoll返回可寫事件,而且

[實驗]關閉TCP對已建立連線的影響

先說結果吧,結果是無影響,已建立的連線依然可以正常使用。 實驗環境 windows10,vs2010 實驗過程 伺服器採用VC程式設計,客戶端使用TCP除錯軟體。 伺服器工作流程 1、建立監聽套接字socket1,繫結埠17000。 2、使用listen函式監聽

accept中的和已連線

int accept(int sockfd, struct sockaddr* cliaddr, socklen_t *addrlen); 該函式用於從已完成連線的佇列隊頭返回下一個已完成連線。 其中sockfd為監聽套接字 cliaddr和addrlen由核心填入

Linux網路程式設計——原始例項:MAC 頭部報文分析

通過《Linux網路程式設計——原始套接字程式設計》得知,我們可以通過原始套接字以及 recvfrom( ) 可以獲取鏈路層的資料包,那我們接收的鏈路層資料包到底長什麼樣的呢? MAC 頭部(有線區域網) 注意:CRC、PAD 在組包時可以忽略 鏈路層資料包的其中一

Linux 網路程式設計——原始例項:MAC 地址掃描器

如果 A (192.168.1.1 )向 B (192.168.1.2 )傳送一個數據包,那麼需要的條件有 ip、port、使用的協議(TCP/UDP)之外還需要 MAC 地址,因為在乙太網資料包中 MAC 地址是必須要有的。那麼怎樣才能知道對方的 MAC 地址?答案是:它通

Linux 網路程式設計——原始例項:傳送 UDP 資料包

乙太網(Ethernet)報文格式(MAC頭部報文格式): IP 報文格式: UDP 報文格式: 校驗和函式: /******************************************************* 功能:     

在io複用中把設為非阻塞

  往往在select 或 epoll 中把 listen_socket 設定為非阻塞 O_NONBLOCK 原因是出在 accept 上, 比如有這麼一個客戶端 : RST客戶端 當這個select或epoll 的伺服器非常繁忙時, 有這麼一個一連線就斷開的客戶端,

連線的區別

摘要:對於伺服器程式設計中最重要的一步等待並接受客戶的連線,那麼這一步在程式設計中如何完成,accept函式就是完成這一步的。它從核心中取出已經建立的客戶連線,然後把這個已經建立的連線返回給使用者程式,此時使用者程式就可以與自己的客戶進行點到點的通訊了。 accept函式等

TCP如何區分和已連線???

2.10 TCP埠號與併發伺服器 併發伺服器中主伺服器迴圈通過派生一個子程序來處理每個新的連線。如果一個子程序繼續使用伺服器眾所周知的埠來服務一個長時間的請求,那將發生什麼?讓我們來看一個典型的序列。首先,在主機freebsd上啟動伺服器,該主機是多宿的,其IP地址為12.106.32.254和192.1

連線

摘要:對於伺服器程式設計中最重要的一步等待並接受客戶的連線,那麼這一步在程式設計中如何完成,accept函式就是完成這一步的。它從核心中取出已經建立的客戶連線,然後把這個已經建立的連線返回給使用者程式,此時使用者程式就可以與自己的客戶進行點到點的通訊了。 accept函式

Linux網路程式設計——原始程式設計

原始套接字的建立 int socket ( int family, int type, int protocol ); 引數: family:協議族 這裡寫 PF_PACKET type:  套接字類,這裡寫 SOCK_RAW protocol:協議類別,指定可以接收或傳送的資料包型別,不能寫

Linux網路程式設計 tcp程式碼

本次介紹一下TCP協議下的套接字程式碼,總體來看,tcp協議比udp協議更加安全可靠,無論是從使用者使用的角度還是從編寫程式碼的角度,你會發現與udp不同的是tcp在每次通訊前,伺服器端和客戶端都會進行一次連線,連線成功後,才可以進行相互間的通訊。 套接字

Linux網路程式設計之選項設定

轉自 http://blog.csdn.net/chenjin_zhong/article/details/7268939 1.介紹 在Linux網路程式設計中,有時需要設定地址複用,允許傳送廣播包,將主機加入某個多播組,設定傳送與接收緩衝區的大小,設定傳送與接收的超

python 網路程式設計 TCP例項

一. 伺服器端程式碼tcpServer.py: from socket import * from time import ctime #HOST變數為空,表示bind()函式可以繫結在所有有效的地址上 HOST = '' PORT = 21234 #設定緩衝大小為1

linux網路程式設計之介面)、ip、埠理解

它是網路通訊過程中端點的抽象表示,包含進行網路通訊必需的五種資訊:連線使用的協議,本地主機的IP地址,本地程序的協議埠,遠地主機的IP地址,遠地程序的協議埠。或者說,套接字,是支援TCP/IP的網路通訊的基本操作單元,可以看做是不同主機之間的程序進行雙向通訊的端點,簡單的說就是通訊的兩方的一種約定,用套接字中

Linux Socket學習 -- 無名 AF_UNIX

來源: http://mylxiaoyi.iteye.com/blog/313863 無名套介面 套介面並不總是需要有一個地址。例如, socketpair函式建立了兩個彼此相連的兩個套介面,但是卻沒有地址。實際上,他們是無名套介面。想像一下冷戰期間美國總統與蘇聯之間的紅

Linux詳解---epoll模式下的IO多路複用伺服器

1 epoll模型簡介 epoll可是當前在Linux下開發大規模併發網路程式的熱門人選,epoll 在Linux2.6核心中正式引入,和select相似,其實都I/O多路複用技術而已,並沒有什麼神祕的。 其實在Linux下設計併發網路程式,向來不缺少方法,比如典型的Apache模型(Proce

Linux詳解(十)---epoll模式下的IO多路複用伺服器

1 epoll模型簡介 epoll可是當前在Linux下開發大規模併發網路程式的熱門人選,epoll 在Linux2.6核心中正式引入,和select相似,其實都I/O多路複用技術而已,並沒有什麼神祕的。 其實在Linux下設計併發網路程式,向來不缺少

用原始實現網路

 作者:張志強 下載原始碼 1、引言    網路監聽工具(sinff)是提供給網路管理員的一類管理工具。在乙太網中(Ethernet),當網路上連線多臺計算機時,某瞬間只能有一臺計算機可以傳送資料。乙太網中,資料是以被稱為幀的資料結構為單位進行交換的。通常,在計算機網路上交換