600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > libevent使用IOCP网络模型的示例

libevent使用IOCP网络模型的示例

时间:2021-03-03 04:46:02

相关推荐

libevent使用IOCP网络模型的示例

这段时间抽空学习了一下强大的网络库libevent,其使用标准C语言编写,支持Windows、Linux、Mac等等主流操作系统,早期版本不支持Windows的IOCP,最新版本已经添加上了,在网上找了一下资料,发现使用IOCP的libevent示例太少,于是结合网上的资料,自己整理编写了一下libevent使用IOCP的小例子。该示例同时支持IPV4以及IPV6的连接。

#ifdef __cplusplusextern "C"{#endif//包含所需要的头文件#include "event2/event.h"#include "event2/listener.h"#include "event2/bufferevent.h"#include "event2/thread.h"#include "event2/buffer.h"#ifdef __cplusplus};#endif#ifdef _MSC_VER#pragma comment(lib,"ws2_32.lib")#pragma comment(lib,"libevent_core.lib")#endif//监听回调函数void listener_cb(evconnlistener *listener, evutil_socket_t fd,struct sockaddr *sock, int socklen, void *arg); //从Socket接收消息的回调函数void socket_read_cb(bufferevent *bev, void *arg);//从Socket事件的回调函数void socket_event_cb(bufferevent *bev, short events, void *arg); int main(){ WORD wVersionRequested;WSADATA wsaData;int err;/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */wVersionRequested = MAKEWORD(2, 2);//这里必须初始化网络,不然会创建Socket失败err = WSAStartup(wVersionRequested, &wsaData);if (err != 0) {/* Tell the user that we could not find a usable *//* Winsock DLL. */printf("WSAStartup failed with error: %d\n", err);return 1;}struct sockaddr_in sin;memset(&sin, 0, sizeof(struct sockaddr_in));sin.sin_family = AF_INET;sin.sin_port = htons(2000);struct sockaddr_in6 sin6;memset(&sin6, 0, sizeof(struct sockaddr_in6));sin6.sin6_family = AF_INET6;sin6.sin6_port = htons(2000);//告诉libEvent使用Windows线程//这句是必须的,不然会导致event_base_dispatch时一直处于Sleep状态,无法正常工作evthread_use_windows_threads();struct event_config* cfg = event_config_new();event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);//根据CPU实际数量配置libEvent的CPU数SYSTEM_INFO si;GetSystemInfo(&si);event_config_set_num_cpus_hint(cfg,si.dwNumberOfProcessors);event_base *base;base = event_base_new_with_config(cfg); event_config_free(cfg);// 绑定并监听IPV4端口evconnlistener *listener = evconnlistener_new_bind(base, listener_cb, base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 10, (struct sockaddr*)&sin, sizeof(sin));// 绑定并监听IPV6端口evconnlistener *listener6 = evconnlistener_new_bind(base, listener_cb, base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 10, (struct sockaddr*)&sin6, sizeof(sin6));//事件分发处理event_base_dispatch(base); evconnlistener_free(listener);evconnlistener_free(listener6);event_base_free(base);WSACleanup();return 0; }//一个新客户端连接上服务器了 //当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的//文件描述符为fdvoid listener_cb(evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sock, int socklen, void *arg) { char Buffer[256];sockaddr_in* addr = (sockaddr_in*)sock;evutil_inet_ntop(addr->sin_family,&addr->sin_addr,Buffer,sizeof(Buffer));printf("accept a client %d,IP:%s\n", fd,Buffer);event_base *base = (event_base*)arg; //为这个客户端分配一个bufferevent bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE); bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL); bufferevent_enable(bev, EV_READ | EV_PERSIST); }void socket_read_cb(bufferevent *bev, void *arg) { char msg[4096];size_t len;// 这里一行一行的读取char* p = evbuffer_readln(bufferevent_get_input(bev),&len,EVBUFFER_EOL_ANY);if(p){// 如果输入exit或者quit则退出程序// 可以使用event_base_loopexit或者event_base_loopbreak// 它们的区别是前者会把事件处理完才退出,后者是立即退出if(!strcmp(p,"exit"))event_base_loopexit(bufferevent_get_base(bev),NULL);else if (!strcmp(p,"quit"))event_base_loopbreak(bufferevent_get_base(bev));printf("recv data:%s\n", p); int n = sprintf_s(msg,"srv recv data:%s\n",p);//发送消息给客户端bufferevent_write(bev, msg, n );// 这里记得把分配的内存释放掉,不然会内存泄漏free(p);}}void socket_event_cb(bufferevent *bev, short events, void *arg) { if (events & BEV_EVENT_EOF) printf("connection closed\n"); else if (events & BEV_EVENT_ERROR) printf("some other error\n"); //这将自动close套接字和free读写缓冲区 bufferevent_free(bev); }

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。