1. 程式人生 > >I/O複用___libevent

I/O複用___libevent

一、情景再現

典型的C/S模式是這樣的,不妨以多執行緒為例來說明:ser啟動一個專門用於處理cli連線請求的執行緒,一旦需要連線,就accept,與cli建立連線,連線好後將事物交付給其他執行緒去處理。

當我們從事件監聽的角度讀看待這個流程的話,伺服器端起始有兩處需要被監聽:1、until有了連線請求才去accept;2、連線建立好了之後,until有了資料傳輸才會有recv或者send操作。

二、程式碼實現

2.1 伺服器端

#include<iostream>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<event.h>
#include<assert.h>
using namespace std;

void listen_cb(int fd, short event, void* arg); //是否需要accept
void c_cb(int clifd, short event, void *arg); //是否需要recv

int main()
{
    struct event_base *lib = event_base_new(); //初始化libevent

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    assert(-1 != fd);

    struct sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_port = htons(6000);
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int res = bind(fd, (struct sockaddr*)&ser, sizeof(ser));
    assert(-1 != res);

    assert(-1 != listen(fd, 5));

    //建立事件
    struct event* listen_event = event_new(lib, fd, EV_READ|EV_PERSIST, listen_cb, lib);
    assert(NULL != listen_event);

    event_add(listen_event, NULL); //將事件新增到列表中去
    event_base_dispatch(lib); //迴圈監聽
    return 0;
}

//主要是監聽是否要accept()
void listen_cb(int fd, short event, void *arg)
{
    struct event_base* lib = (struct event_base*)arg;
    struct sockaddr_in cli;
    socklen_t len = sizeof(cli);
    int clifd = accept(fd, (struct sockaddr*)&cli, &len);
    assert(-1 != clifd);

    //針對是否需要向已連線的客戶端提供服務
    struct event* cli_event = event_new(lib, clifd, EV_READ, c_cb, lib);
    assert(NULL != cli_event);

    event_add(cli_event, NULL);
}

//主要是監聽是否要recv或者send
void c_cb(int clifd, short event, void *arg)
{
    char buf[128] = {'\0'};
    int n = recv(clifd, buf, 127, 0);//一旦連線好的客戶端不再發送資料n=0
    if(n > 0)
    {
        cout<<buf<<endl;
        assert(-1 != send(clifd, "OK", sizeof("OK"), 0));
    }
    else
    {
        close(clifd);
    }
}                        

2.2客戶端

#include<iostream>
#include<event.h>
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr()
#include<assert.h>
using namespace std;


int main()
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    assert(-1 != fd);

    struct sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_port = htons(6000);
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int res= connect(fd, (struct sockaddr*)&ser, sizeof(ser));
    assert(-1 != res);

    assert(-1 != send(fd, "hello", sizeof("hello"), 0));

    char buf[128] = {'\0'};
    int n = recv(fd, buf, 127, 0);
    if(n > 0);
        cout<<buf<<endl;
    
    return 0;
}

2.3執行結果