linux 下使用libevent實現伺服器小例子

來源:互聯網
上載者:User
// 伺服器端#include <iostream>#include <event.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <string.h>#include <fcntl.h>using namespace std;struct event_base* main_base;static const char MESSAGE[] ="Hello, World!\n";void accept_handle(const int sfd, const short event, void *arg){cout<<"accept handle"<<endl;struct sockaddr_in addr;socklen_t addrlen = sizeof(addr);int fd = accept(sfd, (struct sockaddr *) &addr, &addrlen); //處理串連struct bufferevent* buf_ev;buf_ev = bufferevent_new(fd, NULL, NULL, NULL, NULL);buf_ev->wm_read.high = 4096;cout<<"event write"<<endl;bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));}int main(){cout<<"hello man!"<<endl;// 1. 初始化EVENTmain_base = event_init();if(main_base)cout<<"init event ok!"<<endl;// 2. 初始化SOCKETint sListen;// Create listening socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// Bindstruct sockaddr_in server_addr;bzero(&server_addr,sizeof(struct sockaddr_in));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);int portnumber = 8080;server_addr.sin_port = htons(portnumber);/* 捆綁sockfd描述符  */if(bind(sListen,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1){cout<<"error!"<<endl;return -1;}// Listen::listen(sListen, 3);cout<<"Server is listening!\n"<<endl;/*將描述符設定為非阻塞*/int flags = ::fcntl(sListen, F_GETFL);flags |= O_NONBLOCK;fcntl(sListen, F_SETFL, flags);// 3. 建立EVENT 事件struct event ev;event_set(&ev, sListen, EV_READ | EV_PERSIST, accept_handle, (void *)&ev);// 4. 事件添加與刪除event_add(&ev, NULL);// 5. 進入事件迴圈event_base_loop(main_base, 0);cout<<"over!"<<endl;}

/******* 用戶端程式  client.c ************/#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/types.h>#include <arpa/inet.h>int main(int argc, char *argv[]){        int sockfd;        char buffer[1024];        struct sockaddr_in server_addr;        struct hostent *host;        int portnumber,nbytes;        if((host=gethostbyname("10.1.39.93"))==NULL)        {                fprintf(stderr,"Gethostname error\n");                exit(1);        }        if((portnumber=atoi("8080"))<0)        {                fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);                exit(1);        }        /* 客戶程式開始建立 sockfd描述符  */        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)        {                fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));                exit(1);        }        /* 客戶程式填充服務端的資料       */        bzero(&server_addr,sizeof(server_addr));        server_addr.sin_family=AF_INET;        server_addr.sin_port=htons(portnumber);        server_addr.sin_addr=*((struct in_addr *)host->h_addr);        /* 客戶程式發起串連請求         */        if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)        {                fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));                exit(1);        }        /* 串連成功了           */        if((nbytes=read(sockfd,buffer,1024))==-1)        {                fprintf(stderr,"Read Error:%s\n",strerror(errno));                exit(1);        }        buffer[nbytes]='\0';        printf("I have received:%s\n",buffer);        /* 結束通訊     */        close(sockfd);        exit(0);}

(2)事件設定

      socket服務建立後,就可以進行事件設定。我們使用event_set來設定事件對象,其傳入參數包括事件根基(event_base對象),描述符,事件類型,事件發生時的回呼函數,回呼函數傳入參數。其中事件類型包括EV_READ、EV_WRITE、EV_PERSIST,EV_PERSIST和前兩者結合使用,表示該事件為持續事件。

struct event ev;

event_set(&ev, listen_fd, EV_READ | EV_PERSIST, accept_handle, (void *)&ev);

(3)事件添加與刪除

         事件設定好後,就可以將其加入事件隊列。event_add用來將事件加入,它接受兩個參數:要添加的事件和時間的逾時值。 如果需要將事件刪除,可以使用event_del來完成。event_del函數會取消所指定的事件。

event_add(&ev, NULL)

3 進入事件迴圈

    事件成功添加後就是萬事具備只欠東風了,libevent提供了多種方式來進入事件迴圈,我個人常用的是event_dispatch和event_base_loop,前者最後實際是使用當前事件根基來調用event_base_loop。

   event_base_loop(main_base, 0);

 

4 處理串連

     到這裡為止,大家已經完成了事件的設定、事件的添加並進入到了事件迴圈。但是當事件發生時(這裡就是串連建立)如何處理呢? 聰明的使用者會想到前面我們在事件設定時指定的回呼函數accept_handle。沒錯,當串連建立時回呼函數accept_handle會自動的得到調用。

       對於緩衝區的讀寫在非阻塞式網路編程中是一個難以處理的問題,幸運的是libevent提供了bufferevent和evbuf來替我們完成該項工作。這裡我們採用bufferevent來處理。

(1)產生bufferevent對象

      使用bufferevent_new對象來產生bufferevent對象,並分別指定讀、寫、串連錯誤時的處理函數和函數傳入參數。

(2) 設定讀取量

bufferevent的讀事件啟用以後,即使使用者沒有讀取完bufferevent緩衝區中的資料, bufferevent讀事件也不會再次被啟用。因為bufferevent的讀事件是由其所監控的描述符的讀事件啟用的,只有描述符可讀,讀事件才會被啟用。可通過設定wm_read.high來控制bufferevent從描述符緩衝區中讀取的資料量。

(3) 將事件加入事件隊列

和前面一樣,在事件設定好後,需將事件加入到事件隊列中, 不過bufferevent的有自己專門的加入函數bufferevent_base_set和啟用函數bufferevent_enable。

bufferevent接收兩個參數事件根基個事件對象,前者用來指定事件將加入到哪個事件根基中,後者說明需將那個bufferevnet事件加入。(在多線程的情況下,每個線程可能有自己單獨的事件根基)

在bufferevent初始化完畢後,可以使用bufferevent_enable和bufferevent_disable反覆的啟用與禁止事件,其接收參數為事件對象和事件標誌。其中標誌參數為EV_READ和EV_WRITE。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.