libevent学习之三:简单的服务器和客户端
1.服务器
#include <stdio.h> #include <time.h> #include <event2/bufferevent.h> #include <event2/buffer.h> #include <event2/listener.h> #include <event2/util.h> #include <event2/event.h> const int PORT = 2500; const int BUFFER_SIZE = 1024; void listener_cb(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *); void conn_writecb(struct bufferevent *, void *); void conn_readcb(struct bufferevent *, void *); void conn_eventcb(struct bufferevent *, short, void *); void delay(int ms); int main(int argc, char **argv) { printf("I am server "); #ifdef WIN32 WSAData wsaData; WSAStartup(MAKEWORD(2, 0), &wsaData); #endif struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT); struct evconnlistener *listener; struct event_base *base = event_base_new(); if (!base) { printf("Could not initialize libevent "); return 1; } listener = evconnlistener_new_bind(base, listener_cb, (void *)base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { printf("Could not create a listener "); return 1; } event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); printf("done "); return 0; } void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data) { printf("Detect an connection "); struct event_base *base = (struct event_base *)user_data; struct bufferevent *bev; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); if (!bev) { printf("Could not create a bufferevent "); event_base_loopbreak(base); return; } bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL); bufferevent_enable(bev, EV_READ|EV_WRITE); //服务器监听到连接时,给客户端发送第一条消息 char *reply_msg = "I receive a message from server"; bufferevent_write(bev, reply_msg, strlen(reply_msg)); } //conn_writecwritecb函数将在bufferevent中的output evbuffer缓冲区发送完成后被调用。 //此时evbuffer_get_length(output) = 0,说明output evbuffer缓冲区被清空。 //假设发现有10000条记录要发送出去,1次发送10000条将占用大量内存,所以,我们要分批发送 //先发送100条数据,假设每条数据为1024字节bufferevent_write(bev,buf,1024 *100); //系统在这100条记录发送完成后将调用conn_writecbb回调函数,然后在该函数中循环发送剩下的 //数据 void conn_writecb(struct bufferevent *bev, void *user_data) { // struct evbuffer *output = bufferevent_get_output(bev); // if (evbuffer_get_length(output) == 0) // { // printf("Output evbuffer is flushed "); // bufferevent_free(bev); // } //delay 1 second delay(1000); static int msg_num = 1; char reply_msg[1000] = {" "}; char *str = "I receive a message from server "; memcpy(reply_msg,str,strlen(str)); sprintf(reply_msg+strlen(str),"%d",msg_num); bufferevent_write(bev, reply_msg, strlen(reply_msg)); msg_num++; } void conn_readcb(struct bufferevent *bev, void *user_data) { struct evbuffer *input =bufferevent_get_input(bev); size_t sz=evbuffer_get_length(input); if (sz > 0) { char msg[BUFFER_SIZE] = {" "}; bufferevent_read(bev, msg, sz); printf("%s ", msg); } } void conn_eventcb(struct bufferevent *bev, short events, void *user_data) { if (events & BEV_EVENT_EOF) { printf("Connection closed "); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s ",strerror(errno)); } bufferevent_free(bev); } void delay(int ms) { clock_t start = clock(); while(clock() - start < ms); }
2.客户端
#include <stdio.h> #include <time.h> #include <event2/bufferevent.h> #include <event2/buffer.h> #include <event2/listener.h> #include <event2/util.h> #include <event2/event.h> const int PORT = 2500; const int BUFFER_SIZE = 1024; void conn_writecb(struct bufferevent *, void *); void conn_readcb(struct bufferevent *, void *); void conn_eventcb(struct bufferevent *, short, void *); void delay(int ms); int main() { printf("I am client "); #ifdef WIN32 WSAData wsaData; WSAStartup(MAKEWORD(2, 0), &wsaData); #endif struct sockaddr_in srv; memset(&srv, 0, sizeof(srv)); srv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); srv.sin_family = AF_INET; srv.sin_port = htons(PORT); struct event_base *base = event_base_new(); if (!base) { printf("Could not initialize libevent "); return 1; } struct bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL); int flag=bufferevent_socket_connect(bev, (struct sockaddr *)&srv,sizeof(srv)); bufferevent_enable(bev, EV_READ | EV_WRITE); if(-1==flag) { printf("Connect failed "); return 1; } event_base_dispatch(base); event_base_free(base); printf("done "); return 0; } //conn_writecwritecb函数将在bufferevent中的output evbuffer缓冲区发送完成后被调用。 //此时evbuffer_get_length(output) = 0,说明output evbuffer缓冲区被清空。 //假设发现有10000条记录要发送出去,1次发送10000条将占用大量内存,所以,我们要分批发送 //先发送100条数据,假设每条数据为1024字节bufferevent_write(bev,buf,1024 *100); //系统在这100条记录发送完成后将调用conn_writecbb回调函数,然后在该函数中循环发送剩下的 //数据 void conn_writecb(struct bufferevent *bev, void *user_data) { // struct evbuffer *output = bufferevent_get_output(bev); // if (evbuffer_get_length(output) == 0) // { // printf("Output evbuffer is flushed "); // bufferevent_free(bev); // } //delay 1 second delay(1000); static int msg_num = 1; char reply_msg[1000] = {" "}; char *str = "I receive a message from client "; memcpy(reply_msg,str,strlen(str)); sprintf(reply_msg+strlen(str),"%d",msg_num); bufferevent_write(bev, reply_msg, strlen(reply_msg)); msg_num++; } void conn_readcb(struct bufferevent *bev, void *user_data) { struct evbuffer *input =bufferevent_get_input(bev); size_t sz=evbuffer_get_length(input); if (sz > 0) { char msg[BUFFER_SIZE] = {" "}; bufferevent_read(bev, msg, sz); printf("%s ", msg); } } void conn_eventcb(struct bufferevent *bev, short events, void *user_data) { if (events & BEV_EVENT_EOF) { printf("Connection closed "); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s ",strerror(errno)); } else if( events & BEV_EVENT_CONNECTED) { printf("Connect succeed "); //客户端链接成功后,给服务器发送第一条消息 char *reply_msg = "I receive a message from client"; bufferevent_write(bev, reply_msg, strlen(reply_msg)); return ; } bufferevent_free(bev); } void delay(int ms) { clock_t start = clock(); while(clock() - start < ms); }
3.运行效果
先启动服务器,然后启动客户端,效果如下图所示。
服务器
客户端
4.源码
源码默认使用的是MingW版本的libevent头文件和库,也包含Windows版本的libevent头文件和库,后缀为_win。
libevent的编译和使用可以参考:libevent学习之二:Windows7(Win7)下编译libevent
如何调试libevent可参考:libevent学习之四:vs2012编译libevent-2.1.8-stable源码 可调试
源码链接:详见http://blog.csdn.net/caoshangpa/article/details/52839488的评论
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。