从github上下载压缩包
将压缩包拷贝到unbuntu22.04的虚拟机上面
wuhaonan:match-game$ls
libevent-2.1.12-stable libevent-2.1.12-stable.tar.gz
wuhaonan:match-game$tar -zxvf libevent-2.1.12-stable.tar.gz
cd libevent-2.1.12-stable
wuhaonan:libevent-2.1.12-stable
wuhaonan:libevent-2.1.12-stable$cd cmake/
wuhaonan:libevent-2.1.12-stable$mkdir build && cd build
wuhaonan:build$ls
wuhaonan:build$cmake ..
wuhaonan:build$make
wuhaonan:build$sudo make install
wuhaonan:build$sudo ldconfig # 更新库缓存
wuhaonan:build$ls /usr/local/include/event2/event.h # 系统路径
测试libevent是否安装成功
demo.c
#include <event2/event.h>
#include <stdio.h>
/*
# 默认系统路径(/usr/local)
gcc demo.c -o demo -levent
# 自定义路径(如$HOME/local)
gcc demo.c -o demo -I$HOME/local/include -L$HOME/local/lib -levent
解决运行时库路径问题
若安装到非系统路径,需设置LD_LIBRARY_PATH:
bash
复制
export LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH
./demo
*/
int main() {
struct event_base *base = event_base_new();
printf("LibEvent initialized successfully!\n");
event_base_free(base);
return 0;
}
执行gcc demo.c -o demo -levent
wuhaonan:match-game$gcc demo.c -o demo -levent
wuhaonan:match-game$./demo
LibEvent initialized successfully!
经过测试安装成功
简单测试libevent
注:还需要安装cJSON
#include <event2/event.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <cjson/cJSON.h> // cJSON 头文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// GET请求处理函数
// 第一个参数req是HTTP请求对象,第二个参数arg是用户自定义参数,这里没有使用
void handle_get(struct evhttp_request *req, void *arg)
{
// 获取请求URI 将http请求的uri作为参数传递
const char *uri = evhttp_request_get_uri(req);
if (uri == NULL) {
printf("URI is NULL\n");
return;
}
// 打印请求URI
printf("GET %s\n", uri);
// 创建JSON响应
cJSON *root = cJSON_CreateObject(); // 创建JSON对象 准备构建响应数据
if (root == NULL)
{
printf("创建JSON对象失败\n");
return;
}
// 构建响应数据
cJSON_AddStringToObject(root, "status", "success"); // 添加字符串键值对
cJSON_AddStringToObject(root, "message", "欢迎使用JSON服务"); // 添加字符串键值对
// 构建JSON响应字符串 将JSON对象转换为JSON字符串
char *json_str = cJSON_Print(root); // 打印JSON对象
if (json_str == NULL)
{
printf("打印JSON对象失败\n");
cJSON_Delete(root); // 释放JSON对象
return;
}
struct evbuffer *buf = evbuffer_new(); // 创建缓冲区
if (buf == NULL)
{
printf("创建缓冲区失败\n");
cJSON_free(json_str); // 释放JSON字符串
cJSON_Delete(root); // 释放JSON对象
return;
}
evbuffer_add_printf(buf, "%s", json_str); // 添加JSON字符串到缓冲区
// 设置JSON响应头
// 为HTTP响应设置Content-Type头,指定响应的内容类型为JSON。这有助于客户端(如浏览器或API调用者)正确解析服务器返回的数据格式。
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/json"); // 设置响应头
evhttp_add_header(evhttp_request_get_output_headers(req), "Access-Control-Allow-Origin", "*"); // 添加跨域支持
evhttp_send_reply(req, HTTP_OK, "OK", buf); // 发送HTTP响应
// 释放资源
evbuffer_free(buf); // 释放缓冲区
cJSON_Delete(root); // 释放JSON对象
free(json_str); // 释放JSON字符串
}
// POST请求处理函数(JSON解析)
void handle_post(struct evhttp_request *req, void *arg)
{
// 获取请求体中的数据
struct evbuffer *input_buf = evhttp_request_get_input_buffer(req); // 获取请求输入缓冲区
if (input_buf == NULL)
{
printf("获取请求输入缓冲区失败\n");
return;
}
size_t len = evbuffer_get_length(input_buf); // 获取输入缓冲区长度
if (len == 0)
{
printf("输入缓冲区为空\n");
return;
}
// +1是为了在结尾添加一个空字符,以便于字符串处理
char *post_data = (char*)malloc(len + 1); // 分配内存
if (post_data == NULL)
{
printf("分配内存失败\n");
return;
}
// 从输入缓冲区中拷贝数据到post_data
evbuffer_copyout(input_buf, post_data, len); // 拷贝缓冲区数据到post_data
post_data[len] = '\0'; // 结尾添加空字符
printf("原始POST数据: %s\n", post_data); // 打印原始POST数据
// 解析JSON数据
cJSON *root = cJSON_Parse(post_data); // 解析JSON字符串
struct evbuffer *retbuf = evbuffer_new(); // 创建缓冲区
if (retbuf == NULL)
{
printf("创建缓冲区失败\n");
free(post_data); // 释放内存
cJSON_Delete(root); // 释放JSON对象
return;
}
if(!root){
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL)
{
fprintf(stderr, "JSON解析错误前: %s\n", error_ptr);
}
evbuffer_add_printf(retbuf, "{\"error\":\"Invalid JSON\"}");
evhttp_send_reply(req, HTTP_BADREQUEST, "Bad Request", retbuf);
goto cleanup;
}
// 提取JSON字段
cJSON *username = cJSON_GetObjectItemCaseSensitive(root, "username"); // 获取username字段
cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age"); // 获取age字段
if(username == NULL || age == NULL) {
printf("JSON数据不完整\n");
evbuffer_add_printf(retbuf, "{\"error\":\"JSON数据不完整\"}");
evhttp_send_reply(req, HTTP_BADREQUEST, "Bad Request", retbuf);
goto cleanup;
}
// 构建响应JSON
cJSON *response = cJSON_CreateObject(); // 创建JSON对象
if (cJSON_IsString(username) && cJSON_IsNumber(age)) {
cJSON_AddStringToObject(response, "status", "success");
cJSON_AddStringToObject(response, "username", username->valuestring);
cJSON_AddNumberToObject(response, "age", age->valueint);
} else {
cJSON_AddStringToObject(response, "error", "字段格式错误");
}
// 发送响应
char *response_str = cJSON_PrintUnformatted(response); // 打印JSON对象
evbuffer_add_printf(retbuf, "%s", response_str); // 添加JSON字符串到缓冲区
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/json"); // 设置响应头
evhttp_add_header(evhttp_request_get_output_headers(req), "Access-Control-Allow-Origin", "*"); // 添加跨域支持
evhttp_send_reply(req, HTTP_OK, "OK", retbuf); // 发送HTTP响应
cleanup:
// 资源清理
evbuffer_free(retbuf);
cJSON_Delete(root);
if (response) cJSON_Delete(response); // 确保response不为NULL
free(post_data);
if (response_str) free(response_str); // 确保response_str不为NULL
}
/*
gcc -o demo demo.c -levent -lcjson
# GET请求测试
curl "http://localhost:8080/api/get?name=John"
# POST测试(JSON格式)
curl -X POST -H "Content-Type: application/json" \
-d '{"username":"张三","age":25}' \
http://localhost:8080/api/post
# 响应结果:
欢迎使用libevent服务!
GET参数 name=John
*/
int main(void)
{
// 事件库会监听各种事件(例如网络套接字上的读写事件,定时器事件等),并在这些事件发生时调用相应的回调函数来处理这些事件。
struct event_base *base = event_base_new(); // 创建事件库
if(base == NULL) {
printf("创建事件库失败\n");
return 1;
}
// 创建HTTP服务器
struct evhttp *http = evhttp_new(base); // 创建HTTP服务器
if(http == NULL) {
printf("创建HTTP服务器失败\n");
return 1;
}
// 设置HTTP服务器的监听地址和端口
if(evhttp_bind_socket(http, "0.0.0.0", 8080) != 0) {
printf("绑定HTTP服务器失败\n");
return 1;
}
// 设置HTTP服务器的回调函数
evhttp_set_cb(http, "/api/get", handle_get, NULL); // 设置GET请求的回调函数
evhttp_set_cb(http, "/api/post", handle_post, NULL); // 设置POST请求的回调函数
printf("HTTP服务器启动成功,监听端口8080\n");
// 事件循环,监听并处理事件 会阻塞,直到事件循环结束
event_base_dispatch(base); // 启动事件循环
// 释放资源
evhttp_free(http); // 释放HTTP服务器
event_base_free(base); // 释放事件库
return 0;
}