程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> libevent實現echoclient

libevent實現echoclient

編輯:C++入門知識

基於libevent實現了一個簡單的echoclient。之前在網上看到的都是echoserver。這裡演示一下使用libevent進行客戶端編程的基本步驟。

先看代碼:


[cpp]
#include "stdafx.h"  
#include "event2/event.h"  
#include "event2/util.h"  
 
#define ECHO_PORT   8888  
#define ECHO_SERVER "127.0.0.1"  
 
struct echo_context{ 
    struct event_base *base; 
    struct event *event_write; 
    struct event *event_read; 
    const char * echo_contents; 
    int echo_contents_len; 
    int recved; 
}; 
 
void write_cb(evutil_socket_t sock, short flags, void * args) 

    struct echo_context *ec = (struct echo_context *)args;  
 
    int ret = send(sock, ec->echo_contents, ec->echo_contents_len, 0); 
    printf("connected, write to echo server: %d\n", ret); 
    event_add(ec->event_read, 0); 

 
void read_cb(evutil_socket_t sock, short flags, void * args) 

    struct echo_context *ec = (struct echo_context *)args;  
    char buf[128]; 
    int ret = recv(sock, buf, 128, 0); 
     
    printf("read_cb, read %d bytes\n", ret); 
    if(ret > 0) 
    { 
        ec->recved += ret; 
        buf[ret] = 0; 
        printf("recv:%s\n", buf); 
    } 
    else if(ret == 0) 
    { 
        printf("read_cb connection closed\n"); 
        event_base_loopexit(ec->base, NULL); 
        return; 
    } 
    if(ec->recved < ec->echo_contents_len) 
    { 
        event_add(ec->event_read, 0); 
    } 

 
static evutil_socket_t make_tcp_socket() 

    int on = 1; 
    evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
 
    evutil_make_socket_nonblocking(sock); 
#ifdef WIN32  
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *)&on, sizeof(on)); 
#else  
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); 
#endif  
 
    return sock; 

 
static void echo_client(struct event_base *base) 

    evutil_socket_t sock = make_tcp_socket(); 
    struct sockaddr_in serverAddr; 
    struct event * ev_write = 0; 
    struct event * ev_read = 0; 
    struct timeval tv={10, 0}; 
    struct echo_context *ec = (struct echo_context*)calloc(1, sizeof(struct echo_context)); 
     
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(ECHO_PORT); 
#ifdef WIN32  
    serverAddr.sin_addr.S_un.S_addr = inet_addr(ECHO_SERVER); 
#else  
    serverAddr.sin_addr.s_addr = inet_addr(ECHO_SERVER); 
#endif  
    memset(serverAddr.sin_zero, 0x00, 8); 
 
    connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); 
 
    ev_write = event_new(base, sock, EV_WRITE, write_cb, (void*)ec); 
    ev_read = event_new(base, sock, EV_READ , read_cb, (void*)ec); 
 
    ec->event_write = ev_write; 
    ec->event_read = ev_read; 
    ec->base = base; 
    ec->echo_contents = strdup("echo client tneilc ohce\n"); 
    ec->echo_contents_len = strlen(ec->echo_contents); 
    ec->recved = 0; 
 
    event_add(ev_write, &tv); 

 
int _tmain(int argc, _TCHAR* argv[]) 

    struct event_base * base = 0; 
#ifdef WIN32  
    WORD wVersionRequested; 
    WSADATA wsaData; 
 
    wVersionRequested = MAKEWORD(2, 2); 
 
    (void) WSAStartup(wVersionRequested, &wsaData); 
#endif  
 
    base = event_base_new(); 
    echo_client(base); 
    event_base_dispatch(base); 
    event_base_free(base); 
 
    return 0; 

#include "stdafx.h"
#include "event2/event.h"
#include "event2/util.h"

#define ECHO_PORT   8888
#define ECHO_SERVER "127.0.0.1"

struct echo_context{
    struct event_base *base;
    struct event *event_write;
    struct event *event_read;
    const char * echo_contents;
    int echo_contents_len;
    int recved;
};

void write_cb(evutil_socket_t sock, short flags, void * args)
{
    struct echo_context *ec = (struct echo_context *)args;

    int ret = send(sock, ec->echo_contents, ec->echo_contents_len, 0);
    printf("connected, write to echo server: %d\n", ret);
    event_add(ec->event_read, 0);
}

void read_cb(evutil_socket_t sock, short flags, void * args)
{
    struct echo_context *ec = (struct echo_context *)args;
    char buf[128];
    int ret = recv(sock, buf, 128, 0);
   
    printf("read_cb, read %d bytes\n", ret);
    if(ret > 0)
    {
        ec->recved += ret;
        buf[ret] = 0;
        printf("recv:%s\n", buf);
    }
    else if(ret == 0)
    {
        printf("read_cb connection closed\n");
        event_base_loopexit(ec->base, NULL);
        return;
    }
    if(ec->recved < ec->echo_contents_len)
    {
        event_add(ec->event_read, 0);
    }
}

static evutil_socket_t make_tcp_socket()
{
    int on = 1;
    evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    evutil_make_socket_nonblocking(sock);
#ifdef WIN32
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *)&on, sizeof(on));
#else
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
#endif

    return sock;
}

static void echo_client(struct event_base *base)
{
    evutil_socket_t sock = make_tcp_socket();
    struct sockaddr_in serverAddr;
    struct event * ev_write = 0;
    struct event * ev_read = 0;
    struct timeval tv={10, 0};
    struct echo_context *ec = (struct echo_context*)calloc(1, sizeof(struct echo_context));
   
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(ECHO_PORT);
#ifdef WIN32
    serverAddr.sin_addr.S_un.S_addr = inet_addr(ECHO_SERVER);
#else
    serverAddr.sin_addr.s_addr = inet_addr(ECHO_SERVER);
#endif
    memset(serverAddr.sin_zero, 0x00, 8);

    connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

    ev_write = event_new(base, sock, EV_WRITE, write_cb, (void*)ec);
    ev_read = event_new(base, sock, EV_READ , read_cb, (void*)ec);

    ec->event_write = ev_write;
    ec->event_read = ev_read;
    ec->base = base;
    ec->echo_contents = strdup("echo client tneilc ohce\n");
    ec->echo_contents_len = strlen(ec->echo_contents);
    ec->recved = 0;

    event_add(ev_write, &tv);
}

int _tmain(int argc, _TCHAR* argv[])
{
    struct event_base * base = 0;
#ifdef WIN32
    WORD wVersionRequested;
    WSADATA wsaData;

    wVersionRequested = MAKEWORD(2, 2);

    (void) WSAStartup(wVersionRequested, &wsaData);
#endif

    base = event_base_new();
    echo_client(base);
    event_base_dispatch(base);
    event_base_free(base);

 return 0;
}

代碼是在windows上實現的。

使用libevent進行客戶端編程的基本步驟,在《libevent實現http client》中已經提過,基本如下:


初始化event_base(後續要運行事件循環)
創建socket,設置為異步,連接server
創建寫讀寫事件,先將寫事件加入事件循環
在寫事件回調中向server端發送請求並將讀事件加入事件循環
在讀事件回調中處理數據,並根據數據是否讀取完畢決定是否繼續添加讀事件
結合本文的示例代碼,通過event_base_new()創建event_base,在初始化客戶端socket(echo_client)之後,調用event_base_dispatch運行事件循環。

echo_client函數初始化了socket,設置為非阻塞模式,調用connect連接到echoserver,然後添加一個寫事件到事件循環中。當連接成功後,會觸發寫事件。這裡將write_cb作為寫事件的回調,在調用event_new()時傳入。

write_cb()寫入一個字符串,然後添加一個讀事件,在讀事件中讀取echoserver的回應。

基本的過程就是這樣子了。這是個簡單的例子,更復雜的例子,基本流程也是一樣的。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved