- 下载地址: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;
}
编译,生成!