libevent学习一:编译以及测试使用(windows版本)
- https://blog.****.net/u014088524/article/details/87303676
- 下载地址:http://libevent.org/ ,下载版本:libevent-2.0.22-stable.tar.gz
- 解压, 目录为...\libevent-2.0.22-stable(自己的目录)
-
修改以下三个文件,添加宏定义:
在以下3个文件开头添加“#define _WIN32_WINNT 0x0500”
libevent-2.0.21-stable\event_iocp.c
libevent-2.0.21-stable\evthread_win32.c
libevent-2.0.21-stable\listener.c
- 打开VS2015命令工具,切换到解压后的libevent目录,然后执行nmake /f Makefile.nmake命令进行编译,命令如下图所示,
先输入cd/d D:\aa_zhj\a_work\projects\libevent\libevent-2.0.22-stable切换目录,然后输入nmake /f Makefile.nmake进行编译。
编译成功后再libevent-2.0.22-stable目录下生成三个lib文件:
libevent.lib、libevent_core.lib、libevent_extras.lib
5.VS2015下使用lib
新建一个VC++控制台项目:
环境配置:
项目下建一个Lib目录,将上面三个lib文件copy到该目录下。
新建一个Include目录,将libevent-2.0.21-stable\include文件夹下的所有内容和WIN32-Code文件夹下的所有内容拷贝到新建的include目录下,两个event2目录下的文件可合并在一起。
6.项目属性设置
VC++目录:
包含目录,添加上面的Include目录;
库目录,添加上面的Lib目录;
C/C++:
代码生成-->运行库:多线程调试 (/MTd)(Debug下),多线程 (/MT)(Release下)
连接器:
输入:ws2_32.lib;wsock32.lib;libevent.lib;libevent_core.lib;libevent_extras.lib;
ws2_32.lib;wsock32.lib;是用来编译Windows网络相关的程序库。
高级-->编译为:编译为C++代码(/TP),(因为我的工程用到C++的函数所以配置这个)
网上有人推荐配置成TC的也可以,自己根据项目需要
配置忽略项,可以不配置
输入\忽略特定默认库 libc.lib;msvcrt.lib;libcd.lib;libcmtd.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries)
7. 生成lib后,不带调试信息,无法单步进函数里,所以要修改脚本:Makefile.nmake第二行
CFLAGS=$(CFLAGS) /Od /W3 /wd4996 /nologo /Zi
到此为止项目配置好了,我们来写相关的demo代码
-
#include <stdio.h>
-
#include <time.h>
-
#include <io.h>
-
#include <process.h>
-
#include <WinSock2.h>
-
#pragma comment(lib,"ws2_32.lib")
-
#include <event2/bufferevent.h>
-
#include <event2/buffer.h>
-
#include <event2/listener.h>
-
#include <event2/util.h>
-
#include <event2/event.h>
-
#pragma warning(disable:4996)
-
#define MAX_LINE 256
-
void read_cb(struct bufferevent *bev, void *arg) {
-
struct evbuffer *buf = (struct evbuffer *)arg;
-
char line[MAX_LINE + 1];
-
int n;
-
evutil_socket_t fd = bufferevent_getfd(bev);
-
while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) {
-
line[n] = '\0';
-
//将读取到的内容放进缓冲区
-
evbuffer_add(buf, line, n);
-
//搜索匹配缓冲区中是否有==,==号来分隔每次客户端的请求
-
const char *x = "==";
-
struct evbuffer_ptr ptr = evbuffer_search(buf, x, strlen(x), 0);
-
if (ptr.pos != -1) {
-
bufferevent_write_buffer(bev, buf); //使用buffer的方式输出结果
-
}
-
}
-
}
-
void write_cb(struct bufferevent *bev, void *arg) {}
-
void error_cb(struct bufferevent *bev, short event, void *arg) {
-
evutil_socket_t fd = bufferevent_getfd(bev);
-
printf("fd = %u, ", fd);
-
if (event & BEV_EVENT_TIMEOUT) {
-
printf("Timed out\n");
-
}
-
else if (event & BEV_EVENT_EOF) {
-
printf("connection closed\n");
-
}
-
else if (event & BEV_EVENT_ERROR) {
-
printf("some other error\n");
-
}
-
//清空缓冲区
-
struct evbuffer *buf = (struct evbuffer *)arg;
-
evbuffer_free(buf);
-
bufferevent_free(bev);
-
}
-
//回调函数,用于监听连接进来的客户端socket
-
void do_accept(evutil_socket_t fd, short event, void *arg) {
-
int client_socketfd;//客户端套接字
-
struct sockaddr_in client_addr; //客户端网络地址结构体
-
int in_size = sizeof(struct sockaddr_in);
-
//客户端socket
-
client_socketfd = accept(fd, (struct sockaddr *) &client_addr, &in_size); //等待接受请求,这边是阻塞式的
-
if (client_socketfd < 0) {
-
puts("accpet error");
-
exit(1);
-
}
-
//类型转换
-
struct event_base *base_ev = (struct event_base *) arg;
-
//socket发送欢迎信息
-
char * msg = "Welcome to My socket";
-
int size = send(client_socketfd, msg, strlen(msg), 0);
-
//创建一个事件,这个事件主要用于监听和读取客户端传递过来的数据
-
//持久类型,并且将base_ev传递到do_read回调函数中去
-
//struct event *ev;
-
//ev = event_new(base_ev, client_socketfd, EV_TIMEOUT|EV_READ|EV_PERSIST, do_read, base_ev);
-
//event_add(ev, NULL);
-
//创建一个evbuffer,用来缓冲客户端传递过来的数据
-
struct evbuffer *buf = evbuffer_new();
-
//创建一个bufferevent
-
struct bufferevent *bev = bufferevent_socket_new(base_ev, client_socketfd, BEV_OPT_CLOSE_ON_FREE);
-
//设置读取方法和error时候的方法,将buf缓冲区当参数传递
-
bufferevent_setcb(bev, read_cb, NULL, error_cb, buf);
-
//设置类型
-
bufferevent_enable(bev, EV_READ | EV_WRITE | EV_PERSIST);
-
//设置水位
-
bufferevent_setwatermark(bev, EV_READ, 0, 0);
-
}
-
//入口主函数
-
int main() {
-
WORD sockVersion = MAKEWORD(2, 2);
-
WSADATA wsaData;
-
if (WSAStartup(sockVersion, &wsaData) != 0)
-
{
-
return 0;
-
}
-
int server_socketfd; //服务端socket
-
struct sockaddr_in server_addr; //服务器网络地址结构体
-
memset(&server_addr, 0, sizeof(server_addr)); //数据初始化--清零
-
server_addr.sin_family = AF_INET; //设置为IP通信
-
server_addr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
-
server_addr.sin_port = htons(8001); //服务器端口号
-
//创建服务端套接字
-
server_socketfd = socket(PF_INET, SOCK_STREAM, 0);
-
if (server_socketfd < 0) {
-
puts("socket error");
-
return 0;
-
}
-
evutil_make_listen_socket_reuseable(server_socketfd); //设置端口重用
-
evutil_make_socket_nonblocking(server_socketfd); //设置无阻赛
-
//绑定IP
-
if (bind(server_socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) {
-
puts("bind error");
-
return 0;
-
}
-
//监听,监听队列长度 5
-
listen(server_socketfd, 10);
-
//创建event_base 事件的集合,多线程的话 每个线程都要初始化一个event_base
-
struct event_base *base_ev;
-
base_ev = event_base_new();
-
const char *x = event_base_get_method(base_ev); //获取IO多路复用的模型,linux一般为epoll
-
printf("METHOD:%s\n", x);
-
//创建一个事件,类型为持久性EV_PERSIST,回调函数为do_accept(主要用于监听连接进来的客户端)
-
//将base_ev传递到do_accept中的arg参数
-
struct event *ev;
-
ev = event_new(base_ev, server_socketfd, EV_TIMEOUT | EV_READ | EV_PERSIST, do_accept, base_ev);
-
//注册事件,使事件处于 pending的等待状态
-
event_add(ev, NULL);
-
//事件循环
-
event_base_dispatch(base_ev);
-
//销毁event_base
-
event_base_free(base_ev);
-
return 1;
-
}
编译,生成!