libevent(17)evhttp的API及server端代码

libevent evhttp使用 一、libevent evhttp使用 1、基本流程 http服务端使用到的借口函数及流程如下 1)、创建event_base和evhttp struct event_base *event_base_new(void); struct evhttp *evhttp_new(struct event_base *base); 2)、绑定地址和端口 int evhttp_bind_socket(st... 阅读详情
AI摘要

文章介绍了libevent库中的evhttp模块如何处理HTTP请求,包括evhttp_request结构体的字段、主要的API函数如evhttp_new()、evhttp_free()、evhttp_bind_socket()等,以及如何设置回调函数处理请求。此外,还提供了一个简单的服务器端示例,展示了如何接收和响应HTTP请求。

一、evhttp介绍

在libevent中HTTP的实现主要是通过evhttp模块来完成的。当客户端发起一个HTTP请求时,libevent将该请求解析为struct evhttp_request结构体表示,并调用用户设置的请求处理函数进行处理。

struct evhttp_request结构体定义了HTTP请求的各个字段,如请求行、请求头、请求正文等。

struct evhttp_request {
    int major;  // 主版本号
    int minor;  // 次版本号
    enum evhttp_cmd_type type;  	// 请求方法(GET、POST等)
    char *uri;  					// 请求URI
    struct evkeyvalq *input_headers;// 请求头
    struct evbuffer *input_buffer;  // 请求正文
};

enum evhttp_cmd_type {
	EVHTTP_REQ_GET     = 1 << 0,
	EVHTTP_REQ_POST    = 1 << 1,
	EVHTTP_REQ_HEAD    = 1 << 2,
	EVHTTP_REQ_PUT     = 1 << 3,
	EVHTTP_REQ_DELETE  = 1 << 4,
.....
};

二、相关的API

1、evhttp_new()

struct evhttp * evhttp_new(struct event_base *base)
    
base:即指向 `event_base` 结构体的指针,用于处理 HTTP 服务器的事件

evhttp_new 用于创建和初始化一个 evhttp 结构体。evhttp 结构体表示一个 HTTP 服务器,它可以在一个或多个套接字上监听传入的 HTTP 请求,并将这些请求分派给适当的请求处理程序。

2、evhttp_free()

void evhttp_free(struct evhttp* http)

evhttp_free() 用于释放 evhttp 结构体及其相关资源。调用该函数后,将销毁与 evhttp 相关联的所有信息,包括绑定的套接字以及任何未完成的请求。

3、evhttp_bind_socket()

int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)

参数:
    http:指向要绑定的evhttp对象的指针。
    address:要绑定的IP地址。可以是一个IPv4或IPv6地址,也可以是一个域名。如果为NULL,则默认绑定到所有可用地址。
    port:要绑定的端口号。

vhttp_bind_socket用于将HTTP服务器绑定到指定的IP地址和端口号。

4、evhttp_set_gencb()

void
evhttp_set_gencb(struct evhttp *http,
   				 void (*cb)(struct evhttp_request *, void *), 
                 void *cbarg)
    
	第一个参数是指向 evhttp 结构体的指针,表示要设置回调函数的 HTTP 服务器;
	第二个参数是指向回调函数的指针,该回调函数的原型为 void (*cb)(struct evhttp_request *, void *),其中第一个参数是指向当前 HTTP 请求的指针,第二个参数是传递给 evhttp_set_gencb() 函数的第三个参数;
    第三个参数是传递给回调函数的上下文参数 cbarg,它可以是任何数据类型的指针;

evhttp_set_gencb()用于设置通用回调函数。

5、evhttp_set_cb()

evhttp_set_cb(struct evhttp *http, 
			  const char *uri,
    		  void (*cb)(struct evhttp_request *, void *), 
    		  void *cbarg)
	第一个参数是指向 evhttp 结构体的指针,表示要设置回调函数的 HTTP 服务器;
	第二个参数是字符串类型的 URI,表示要注册回调函数的 URI;
	第三个参数是指向回调函数的指针,该回调函数的原型为 void (*cb)(struct evhttp_request *, void *),其中第一个参数是指向当前 HTTP 请求的指针,第二个参数是传递给 evhttp_set_cb() 函数的第四个参数;
	四个参数是传递给回调函数的上下文参数 cbarg,它可以是任何数据类型的指针。

evhttp_set_cb() 用于为 HTTP 服务器注册特定 URI 的请求处理程序回调函数。

6、evhttp_request_get_uri()

const char *
evhttp_request_get_uri(const struct evhttp_request *req) {
	if (req->uri == NULL)
		event_debug(("%s: request %p has no uri\n", __func__, (void *)req));
	return (req->uri);	//返回struct evhttp_reques中的URI
}

该函数只有一个参数,即指向 `evhttp_request` 结构体的指针,表示要获取 URI 的 HTTP 请求

返回HTTP 请求的 URI。URI 是客户端在请求服务器时发送的字符串,该字符串通常包含一个主机名、路径和查询字符串。例如,对于 “http://127.0.0.1/foo?bar=baz” 这样的请求,URI 将是 “/foo?bar=baz”。

7、evhttp_request_get_command()

enum evhttp_cmd_type
evhttp_request_get_command(const struct evhttp_request *req) {
	return (req->type);	//返回struct evhttp_reques中请求方法(GET、POST等)
}

函数返回一个枚举类型 evhttp_cmd_type 值,表示 HTTP 请求使用的方法类型。枚举类型包括以下值:
    EVHTTP_REQ_GET: 使用 GET 方法。
    EVHTTP_REQ_POST: 使用 POST 方法。
    EVHTTP_REQ_HEAD: 使用 HEAD 方法。
    EVHTTP_REQ_PUT: 使用 PUT 方法。
    EVHTTP_REQ_DELETE: 使用 DELETE 方法。
    EVHTTP_REQ_OPTIONS: 使用 OPTIONS 方法。
    EVHTTP_REQ_TRACE: 使用 TRACE 方法。
    EVHTTP_REQ_CONNECT: 使用 CONNECT 方法。
    EVHTTP_REQ_PATCH: 使用 PATCH 方法。

用于获取 HTTP 请求的方法类型。

8、evhttp_request_get_input_headers()

struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
{
	return (req->input_headers);	// 返回struct evhttp_reques中请求头
}

用于获取 HTTP 请求中的输入头部。

9、evhttp_request_get_input_buffer()

struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
{
	return (req->input_buffer);	// 返回struct evhttp_reques中请求正文
}

用于获取 HTTP 请求的输入缓冲区。

10、evhttp_request_get_output_headers()

struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
{
	return (req->output_headers);
}

用于获取 HTTP 请求的输出头部。

11、evhttp_add_header()

int	evhttp_add_header(struct evkeyvalq *headers,
    				  const char *key, 
                      const char *value)
    
第一个参数是指向 evkeyvalq 结构体的指针,表示要添加头部的头部列表;
第二个参数是字符串类型的键名,表示要添加的头部的名称;
第三个参数是字符串类型的键值,表示要添加的头部的值。

用于向 evkeyvalq 结构体表示的头部列表添加一个新的键值对。

(1)如果某个键已经存在于头部列表中,则会将现有键值对的值替换为新的值。

(2)如果要添加多个具有相同名称的头部,请使用逗号分隔它们的值。例如,可以使用"Accept-Encoding: gzip, deflate"来同时添加两个Accept-Encoding头部。

12、evhttp_request_get_output_buffer()

struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
{
	return (req->output_buffer);
}

函数返回一个指向 evbuffer 结构体的指针,该结构体代表了 HTTP 请求的输出缓冲区。可以使用 evbuffer_add() 函数将内容添加到缓冲区中。

用于获取 HTTP 请求的输出缓冲区。

13、evhttp_send_reply()

void
evhttp_send_reply(struct evhttp_request *req, 
                 int code, 
                 const char *reason,
    			 struct evbuffer *databuf)
    
	第一个参数是指向 evhttp_request 结构体的指针,表示要发送响应的 HTTP 请求;
    第二个参数是整数类型的状态码,表示响应的状态码;
    第三个参数是字符串类型的原因短语,表示状态码的原因短语;
    第四个参数是指向 evbuffer 结构体的指针,表示响应正文的内容。

用于向客户端发送 HTTP 响应。

在调用 evhttp_send_reply() 函数之前,必须确保已经设置了响应状态码和必要的响应头部,并且已经将所有响应数据写入到输出缓冲区中。

三、一个server端例子


#include <iostream>
#include <thread>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/http.h>
#include <event2/thread.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>

#define WEBROOT "."
#define DEFAULT_INDEX "index.html"

using namespace std;

void http_cb(struct evhttp_request* request, void* arg){
    cout<<"http_cb"<<endl;
	//1 获取浏览器的请求信息
	//uri
	const char* uri = evhttp_request_get_uri(request);
	cout <<"uri:"<<uri<<endl;
	string cmdtype;
	
	//请求类型 GET POST
	switch(evhttp_request_get_command(request)){
	    case EVHTTP_REQ_GET:
		    cmdtype = "GET";
			break;
		case EVHTTP_REQ_POST:
		    cmdtype = "POST";
			break;
	}
	cout<<"cmdtype:"<<cmdtype<<endl;
	
	//消息报头
	evkeyvalq* headers = evhttp_request_get_input_headers(request);
	cout<<"------------------ headers ------------------"<<endl;
	for(evkeyval* p = headers->tqh_first; p != NULL; p = p->next.tqe_next){
	    cout <<p->key <<":"<<p->value<<endl;
	}
	
	//请求正文(GET为空 POST有表单信息)
	evbuffer* inbuf = evhttp_request_get_input_buffer(request);
	char buf[1024] = {0};
	cout<<"------------------ input data ------------------"<<endl;
	while(evbuffer_get_length(inbuf)){
	   int n = evbuffer_remove(inbuf, buf, sizeof(buf) - 1);
	   if(n > 0){
	       strcpy(buf+n, "\0");
		   cout << buf <<endl;
	   }
	}
	
	//2 回复浏览器
	//分析出请求的文件 uri
	//设置根目录
	//windows上要加上(项目属性 - c/c++预处理器 加上: CRT_SECURE_NO_WARNINGS)
	string filepath = WEBROOT;
	filepath += uri;
	if(strcmp(uri, "/") == 0){
	    filepath += DEFAULT_INDEX;
	}
	
	FILE* fp = fopen(filepath.c_str(), "rb");
	cout<<"filepath:"<<filepath<<endl;
	if(fp){	
	    //状态行 消息报头 响应正文
	    evbuffer* outbuf = evhttp_request_get_output_buffer(request);
		for(; ;){
		    int len = fread(buf, 1, sizeof(buf), fp);
			
			if(len <= 0) break;
			evbuffer_add(outbuf, buf, len);
		}
		
		fclose(fp);
	    evhttp_send_reply(request, HTTP_OK, "", outbuf);
	}else{
	    evhttp_send_reply(request, HTTP_NOTFOUND, "", 0);
		return;
	}
}

int main()
{
#ifdef _WIN32
    //windows初始化socket库
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
#else
    //发送数据给已关闭socket时,忽略管道信息.
    //否则可能导致程序dump.
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
        return -1;
    }
#endif
    cout<<"test httpserver!"<<endl;

    //创建 event_base 对象,一个 event_base 对象相当于一个 Reactor 实例
	event_base *base = event_base_new();
	
	//http服务器
    //1.创建evhttp上下文
	evhttp *evh = evhttp_new(base);
	
	//2.绑定端口和ip
	if(evhttp_bind_socket(evh, "0.0.0.0", 8989) != 0){
	    cout<< "evhttp_bind_socket failed!" <<endl;
	}
    
	//3.设定回调函数
	evhttp_set_gencb(evh, http_cb, 0);
	
    event_base_dispatch(base);
    event_base_free(base);
	evhttp_free(evh);

#ifdef _WIN32
    //清理window的socket库
    WSACleanup();
#endif

    return 0;
}

index.html内容:

<html>
<head>
<title>
demo
</title>
</head>
<body>
hello world
</body>
</html>

运行结果:

 

参考:

libevent高并发网络编程 - 04_libevent实现http服务器 

cpp-Libevhtpevhttp是一个libevent的HTTPAPI一个更灵活的替代品 Libevhtp (evhttp) 是一个 libevent 的 HTTP API 一个更灵活的替代品 立即下载

相关推荐

Multisim仿真入门:单相半波可控整流电路从搭建到波形分析(附避坑指南)

本文为电力电子技术初学者提供了一份详细的Multisim仿真指南,手把手教你从零搭建单相半波可控整流电路。通过对比纯电阻、阻感负载及加入续流二极管后的波形变化,直观理解晶闸管触发、电感续流等核心原理,并附有实用的参数设置与常见问题避坑指南,帮助你将抽象理论转化为可视化的工程实践。

weixin_29208077的博客 343

基于libevent的C++高并发、易扩展HTTP服务迭代之路

在项目或产品开发中,需要用C++实现一个高并发且易扩展的HTTP Server,那么我们可以基于libevent来做这件事情。Libevent提供了HTTP Server等组件,并且支持多线程编程。下面我们一起来看一下实现过程。

Bruce Che 的专栏 3681

车载导航测试,面试常见问题

车载导航测试是汽车软件测试的重要组成部分,涉及验证导航系统的功能、性能、可靠性和用户体验。在面试中,面试官通常会考察候选人的测试思维、问题解决能力和实际经验。以下我将从常见问题类别入手,逐步介绍面试中的高频问题,并提供结构化分析。通过以上结构化准备,你能在面试中自信应对车载导航测试相关问题。用户体验测试关注界面友好性和交互流畅性,安全测试则涉及功能安全和数据隐私。功能测试聚焦于导航核心功能的正确性,如路线规划、位置定位和地图显示。面试官会考察你如何识别、报告和跟踪缺陷,以及熟悉测试工具。

m0_69889939的博客 527

libevent evhttp学习——http服务端

http服务端相对客户端要简单很多,我们仍旧使用libevent-2.1.5版本,服务端接口和2.0版本没有区别基本流程http服务端使用到的借口函数及流程如下 创建event_base和evhttpstruct event_base *event_base_new(void); struct evhttp *evhttp_new(struct event_base *base); 绑定地址和端口i

littlewhite1989的专栏 7045

GROMACS自由能景观图绘制全流程:从PCA分析到Origin 3D可视化(附避坑指南)

本文详细解析了使用GROMACS绘制自由能景观图的全流程,涵盖从PCA分析、数据预处理、自由能计算到最终在Origin中进行3D可视化的完整步骤。文章重点分享了数据处理与格式转换中的常见“避坑”指南,帮助研究者从分子动力学轨迹中有效提取并解读构象自由能信息,深化对生物大分子动力学过程的理解。

oauth7security的博客 309

Scrapy实现微博关键词爬虫(爬虫结果写入mongodb)

话不多说,上代码: spiders文件夹下的microBlogSpider.py里这样写: # -*- coding: utf-8 -*- import scrapy from scrapy import Spider, Request, FormRequest from scrapy.selector import Selector import datetime import random from blogSpider.items import microBlogItem, keyWordItem f

qq_39360565的博客 1779

Ubuntu下libevent库部署与性能优化指南

事件驱动编程是现代网络应用开发的核心范式之一,其通过事件循环机制实现高并发IO处理。libevent作为经典的事件通知库,封装了epoll/kqueue等系统调用,提供跨平台的事件抽象层。该库特别适合开发需要处理大量并发连接的网络服务,如Web服务器、实时通信系统等场景。在Ubuntu系统中部署libevent时,需注意系统依赖、编译优化参数配置以及生产环境调优。通过合理设置--enable-shared等编译选项,并配合内核参数调优(如net.core.somaxconn),可显著提升TCP服务的并发处理

weixin_30471561的博客 383

单细胞数据pseudobulks差异分析实战:从聚合到DESeq2

本文详细介绍了单细胞转录组数据分析中pseudobulks(伪散装)方法的实战流程。通过将同一样本的同类型细胞表达值聚合,模拟Bulk RNA-seq数据,再利用DESeq2进行稳健的差异基因分析。该方法有效降低了单细胞数据的技术噪音,特别适用于样本量有限但追求结果稳定性的研究场景,并提供了完整的R代码实现与结果解读指南。

sea99的博客 761

AI推理引擎:大模型落地的实时操作系统

推理引擎是大模型从训练走向生产的核心枢纽,本质是面向GPU资源的实时操作系统(RTOS),负责显存管理、请求调度与模型生命周期管控。其技术原理深植于CUDA内存模型、动态批处理机制与KV Cache分页优化等底层能力,直接决定服务延迟、吞吐与稳定性。在AI工程化落地中,它承载着高并发、低延迟、高资源利用率的关键技术价值,广泛应用于智能客服、金融风控、实时内容生成等对SLA敏感的工业场景。vLLM的PagedAttention、Triton的dynamic_batching等已成为行业高频实践关键词。

weixin_34297704的博客 322

Java本地AI推理初体验:Jlama+LangChain4j构建离线问答系统

Jlama 是专为 Java 生态设计的现代化大型语言模型(LLM)推理引擎,旨在让开发者无需依赖外部服务即可直接在 Java 应用中运行本地化模型推理。本文将结合Jlama + langchain4j 实现一个本地可运行的简单问答Demo。

2501_92589102的博客 407

【STM32项目】基于AI技术的多功能消防机器人(完整工程资料源码)

机器人通过巡逻扫描环境空间与障碍物、定位导航、探测物体/环境进行建模/自动地图测绘、扫描火焰、获取温湿度大小、获取空气安全情况来判断当前环境地点是否安全,检测到温度过高或检测到易燃、烟雾、有毒气体或摄像头识别到火焰时能够通过高压水泵喷射器来实现火焰隔离工作,蜂鸣器进行现场鸣笛报警,同时将当前环境温湿度大小、空气情况、环境地图、是否安全信息,将各个传感器来接收获取到的信息,实时发送到用户手机中的微信小程序,实现与用户远程监视功能,用户同时也能通过手机与电脑远程下发命令来操控机器人来实现交互功能

嵌入式技术开发 1万+

libevent学习 evhttp

在libevent中,封装了http模块,包括很多相关的接口。

SWELER的博客 907

5、流体-结构相互作用耦合技术详解

本文详细解析了流体-结构相互作用(FSI)的两种核心耦合技术:松散耦合和紧密耦合。通过原理阐述、优缺点分析及实际应用案例,对比了两种方法的适用场景与性能差异,并进一步探讨了高级耦合技术的发展趋势和工程实践方向,为相关领域的研究人员和工程师提供了全面的技术参考。

fanta的博客 205

libevent源码剖析之http

libevent 的 HTTP 框架提供了一种轻量级、异步的方式来处理 HTTP 请求和响应,广泛用于编写简单的或其他与 HTTP 协议相关的程序。它构建在 libevent 的事件机制之上,并充分利用了事件驱动和异步 I/O 的优势,能够高效地处理高并发的 HTTP 请求。

老中医的博客 2031

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

网络编程之http服务器(C/C++)(基于libevent实现)

基于libevent实现一个http服务端服务。

zhoubiaodi的博客 2964

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

libevent evhttp学习——http客户端

基本环境使用版本为libevent-2.1.5,目前为beta版,其中evhttp和旧版区别在于新增了如下接口// 设置回调函数,在包头读取完成后回调 void evhttp_request_set_header_cb (struct evhttp_request *, int(*cb)(struct evhttp_request *, void *))// 设置回调函数,在body有数据返回后回调

littlewhite1989的专栏 1万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

libevent之evhttp异步线程发送消息

libevent的evhttp库如何异步回复消息

拒绝黑盒,享受开源 1654

Libevent库的学习笔记(2)——有关HTTP

============对于服务端=============①创建event_base实例②创建一个evhttp实例,把它绑定到一个base上;③evhttp实例绑定地址和端口④设置服务端的回调函数(全局回调和特定回调)⑤启动事件循环 event_base_dispatch();=============对于客户端=============①创建event_base实例②初始化,创建一个evhttp_connection实例,绑定目标服务器的ip+port。

weixin_58581250的博客 1338

linux-arm之http压缩包接收

配套接口evhttp_request_get_uri,evhttp_request_get_command,evhttp_request_get_input_headers,evhttp_request_get_input_buffer,可以通过查看http头文件阅读接口意思。项目中遇到postman下发数据后主板会收到boundary=--------------------------452654904326336879619854,会出现在http头部,开始内容,结尾处。// 发数据给客户端。

a910200850的专栏 537

2022-3-11 基于libevent/evhttp模块的简易http服务器归纳小结-与前端同事的互侃

libevent的单个base对象并不能处理多并发应用请求;libevent的多线程http服务器,实际就是tcp的多线程并发处理;libevent接收请求似乎是并发接过来,但是处理的时候会报异常;

程序员沙子的专栏 1397

libevent中一些http相关的操作

更详细可以看这里https://monkey.org/~provos/libevent/doxygen/evhttp_8h.html struct evhttp* evhttp_new(struct event_base* base) 创建一个新的HTTP server int evhttp_accept_socket(struct evhttp* http, int fd...

CC_fighting的博客 1502

libevent的http服务详解

libevent的http服务详解 即远程调用,得到一个call ID然后验证外部远程参数 evrpc_request_cb(struct evhttp_request *req, void *arg) { struct evrpc *rpc = arg; // 用来自动解析缓冲区数据的,外部验证参数也是从这里过来的 struct evrpc_req_generic *rpc_state = NULL; // 会模拟一个钩子,在等待事件的到来 if (req->type !=

m0_47178337的博客 2415

网编编程-evhttp小试

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/queue.h> #include <event.h> #include <event2/http.h> #include <event2/http_struct.h> #include <event2/http_compat.h> #include &lt.

算法攻城狮 1363

基于libevent实现http通信

libevent

Ahua!的博客 763

libevent evhttp多线程

evhttp多线程

深之JohnChen的专栏 1869
上一篇: libevent(16)基于zlib进行压缩和解压缩
下一篇: std::function的讲解与实战
老蔡编程
博客等级 码龄23年 48粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值