基于libevent实现了一个简单的echoclient。之前在网上看到的都是echoserver。这里演示一下使用libevent进行客户端编程的基本步骤。
先看代码:
#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; }
使用libevent进行客户端编程的基本步骤,在《libevent实现http client》中已经提过,基本如下:
echo_client函数初始化了socket,设置为非阻塞模式,调用connect连接到echoserver,然后添加一个写事件到事件循环中。当连接成功后,会触发写事件。这里将write_cb作为写事件的回调,在调用event_new()时传入。
write_cb()写入一个字符串,然后添加一个读事件,在读事件中读取echoserver的回应。
基本的过程就是这样子了。这是个简单的例子,更复杂的例子,基本流程也是一样的。