libevent服务GET/POST的简单使用

news2025/1/16 1:34:52

目录

  • 1、前言
  • 2、测试demo
    • 2.1、目录结构
    • 2.2、 测试源码
      • 2.2.1、http_server.cpp
      • 2.2.2、 http_server.h
    • 2.3、 编译
    • 2.4、 运行结果
      • 2.4.1、测试POST
      • 2.4.2 、测试GET请求

1、前言


项目开发中经常需要使用到私有协议和Qt,Android等GUI前端通信,比较常用的使用POSTGET方式带出MESSAGE。实际使用中为了减少工作量和代码复用,经常使用到三方库,比较常用的服务有libevent或boost中的网络库、muduo, 也可自行写一套socket系统调用的二次封装, 当然这种方式不利于快速开发, 学习还是可以的。

这篇文章主要使用libevent库,因为是c写的, 所以掌握libevent非常重要。

  • POST请求比较常用, 特别是针对一些数据比较小的场景,比如控制相关, 业务相关的。当然传图片也可以,传输效果过低不推荐。
  • 针对传输二进制比较大的数据, 可以使用GET方式。

针对以上,这里简单使用http的POST和GET方法解决以上问题。
关联:libevent库,链接libevent 源码地址
jsoncpp的编译和使用参考我的这篇文章: 链接C++库libjsoncpp使用

2、测试demo

测试demo写的比较唐突,所以可能存在一些内存释放等BUG,因此如果向使用一下demo的程序开发,需要renew代码和多调试。


2.1、目录结构

event目录
	|-- libevent头文件
http_server.cpp
	|-- CHttpServer 功能类,里面带main的测试程序 
http_server.h
	|-- CHttpServer 接口
libevent.a
	|-- libevent库
libevent_core.a
	|-- libevent库
libevent_pthreads.a
	|-- libevent库

其中event目录是libevent编译后的头文件, *.a是libevent编译后的库静态文件,如果要链接动态库,请自行编译。

2.2、 测试源码

2.2.1、http_server.cpp

#include <unistd.h>

#include <iostream>
#include <string>
#include <memory>			//shared_ptr,unique_ptr .etc

#include "http_server.h"


CHttpServer::CHttpServer():base_(nullptr), http_(nullptr), serverloopThread_(nullptr),isExit_(true), sock_(nullptr)
{
	if(!serverloopThread_){
		serverloopThread_ = new std::thread(&CHttpServer::serverDispatch, this);
		if(!serverloopThread_){
			std::cout << "创建线程失败!" << std::endl;
		}
	}
}

CHttpServer::~CHttpServer()
{
	if(serverloopThread_){
		serverloopThread_->join();
		delete serverloopThread_; serverloopThread_ = nullptr;
	}
}


int CHttpServer::pic_video_test(struct evhttp_request *_req, const std::string &strPath, const char *strParms/*参数query*/)
{
	/*1. 拿到文件数据*/
	FILE *fp = fopen("/tmp/test.pic", "rb");
	if(!fp)
	{
		return -1;	
	}
	fseek(fp, 0, SEEK_END);
	size_t stream_size = ftell(fp);
	fseek(fp, 0, 0);
	printf("size:%d\n", stream_size);
	char *pStream = (char*)calloc(1, stream_size);
	if(!pStream){
		return -2;
	}

	fread(pStream, 1, stream_size, fp);
	fclose(fp); fp = (FILE*)0;
	
	/*添加一些headers*/
	evhttp_add_header(_req->output_headers, "Server", "帘下有白绿的服务");
	evhttp_add_header(_req->output_headers, "Connection", "close");

	struct evbuffer *buf = evbuffer_new();
	if(!buf){
		
		evhttp_send_error(_req, HTTP_INTERNAL, "Internal Error");
		return -255;
	}

	if(pStream && stream_size > 0){
		
		evhttp_add_header(_req->output_headers, "Content-Type", "img/jpg");
		int ret = evbuffer_add(buf, pStream, stream_size);
		printf("ret:%d\n", ret);

		free(pStream); pStream = 0;
	}else {
		
		
		
#if 0		//增加异常信息响应
		evhttp_add_header(_req->output_headers, "Content-Type", "application/json;charset=UTF-8");
		Json::Value root;
		try {
			root["code"] = 300;
			root["msg"] = "打开文件异常,可能文件不存在或系统错误";
		}catch(std::exception &e){
		
			return -3;
		}

		Json::Value def;
		Json::StreamWriterBuilder::setDefaults(&def);
		def["emitUTF8"] = true;
		def["precisionType"] = "decimal";
		def["precision"] = 6;
		
		def["indentation"] = ""; // 压缩格式,没有换行和不必要的空白字符
		
		
		
		std::ostringstream stream;
		Json::StreamWriterBuilder stream_builder;
		stream_builder.settings_ = def;//Config emitUTF8
		std::unique_ptr<Json::StreamWriter> writer(stream_builder.newStreamWriter());
		writer->write(root, &stream);

		std::string strJson = stream.str();
		evbuffer_add(buf, strJson.c_str(), strJson.length());
#endif
	}

	evhttp_send_reply(_req, HTTP_OK, "done",buf);
	evbuffer_free(buf);
	
	printf("request,response Done.\n");
	return 0;
}



//TODO : GET相关的开发工作

int CHttpServer::method_GET_io_process(struct evhttp_request *req)
{
	if( !req ){
		
		return -1;
	}

	
	const char *uri = evhttp_request_get_uri(req);	//获取URI信息
	struct evhttp_uri *decoded = nullptr;
	const char *path;
	char *decoded_path;
	
	decoded = evhttp_uri_parse(uri);			//解析URI请求信息
	if(!decoded){
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
		return -2;
	}

	path = evhttp_uri_get_path(decoded);	//获取http get请求路径
	if(!path) path="/";
	printf("path:%s\n", path);
	/*We need to decode it, to see what path the user really wanted.*/
	decoded_path = evhttp_uridecode(path, 0, NULL); 	//查询路径相关{char *}, get的请求API
	if(!decoded_path){
		return -3;
		evhttp_send_error(req, HTTP_NOTFOUND, NULL);			//响应http错误信息
		
		
	}
	printf("decoded_path:%s\n", decoded_path);
	//获取uri中的参数部分
	const char * query = evhttp_uri_get_query(decoded); //query 参数, {char *}
	

	
	printf("query:%s\n", query);
	pic_video_test(req, decoded_path, query);
	

	if(decoded)
		evhttp_uri_free(decoded);
	if(decoded_path){
		free(decoded_path);decoded_path = 0;
	}
	
	
	
}



//TODO: POST私有协议相关的开发工作, 业务层
int CHttpServer::method_POST_io_process( struct evhttp_request *req )
{
//	Json::Value root;
	struct evbuffer *pEvbuffer(nullptr);

	pEvbuffer = evhttp_request_get_input_buffer(req);
	if(nullptr == pEvbuffer){
		//需要增加异常的响应, 这里暂忽略
		return -1;
	}
	int nJsonbodySize = 1024 * 10;
	char *pJsonbody = (char*)calloc(nJsonbodySize, sizeof(char));
	if(!pJsonbody){
		
		return -2;
	}

	int nread = 0;
	while(evbuffer_get_length(pEvbuffer)){
		nread += evbuffer_remove(pEvbuffer, pJsonbody, nJsonbodySize-1);
	}

	try {
		//解包{反序列化}
		//Json::Reader reader;
		//reader.parse(pJsonbody, root);
	
	}catch(std::exception &e){

	}
	/*请求数据的输出*/
	//	1. 反序列化的逻辑处理,涉及到jsoncpp的库操作
	// 2. 根据项目业务做数据的转发处理{event}以及配置文件的读写操作
	// 3. 封Json包响应请求  
	//4. 发送

	struct evbuffer *pRespbuffer = evbuffer_new();
	if(!pRespbuffer){
		evhttp_send_error(req, HTTP_INTERNAL, "internal error");
		return -1;
	}

	evhttp_add_header(req->output_headers, "Connection", "close");
	evhttp_add_header(req->output_headers, "Content-Type", "application/json;charset=UTF-8");		//和客户端约定的编码方式,这里用的UTF-8
	std::string strRespJsonBody("这里是协议内相关Json");
	evbuffer_add_printf(pRespbuffer, "%s", strRespJsonBody.c_str());	//向evbuffer中增加message

	evhttp_send_reply(req, 200, "ok", pRespbuffer);					//向socker发送操作
	evbuffer_free(pRespbuffer);										//释放操作

	if(pJsonbody){free(pJsonbody); pJsonbody = (char*)0;}


	return 0;
}




void CHttpServer::serverIoExec(struct evhttp_request *req, void *arg)
{
	CHttpServer *_this = (CHttpServer*)arg;
	if(!req){
		return ;
	}	
	evhttp_cmd_type eMethod = evhttp_request_get_command(req);

	switch(eMethod){
	case EVHTTP_REQ_GET:
	{
		
		_this->method_GET_io_process(req);
	}break;
	case EVHTTP_REQ_POST:
	{
		
		_this->method_POST_io_process(req);
	}break;
	default:
		std::cout << "未知http方法" << std::endl;
	}

	return;
}

void CHttpServer::serverDispatch()
{
	pthread_setname_np(pthread_self(), "ServerLoop");
	evthread_use_pthreads();
	base_ = event_base_new();
	if(nullptr == base_){
		std::cout << "create event_base failure!" << std::endl;
		goto FREE_BASE;
	}

	if(!(http_ = evhttp_new(base_))){
		std::cout << " Create a new HTTP server failure!" << std::endl;
		
		goto FREE_BASE;
	}

	evhttp_set_gencb(http_, CHttpServer::serverIoExec, (void*)this);

	sock_ = evhttp_bind_socket_with_handle(http_, "0.0.0.0", DEFAULT_LISTEN_PORT);
	if(nullptr == sock_){
		
		std::cout << "" << std::endl;
		goto FREE_HTTP;
	}

	event_base_dispatch(base_);	
	

FREE_SOCK:
	if(http_ && sock_){
		evhttp_del_accept_socket(http_, sock_); sock_ = nullptr;
	}

		
FREE_HTTP:
	if(http_){evhttp_free(http_); http_ = nullptr;}
FREE_BASE:
	if(base_){event_base_free(base_); base_ = nullptr;}
	
}	

void CHttpServer::loop()
{
	while(!isExit_){
		sleep(2);			//这里使用select精准时钟比较合理,待修改
	}
}

int main(int argc, char *argv[])
{
	std::shared_ptr<CHttpServer> impl = std::make_shared<CHttpServer>();
	if(impl){
		impl->loop();
	}

	return 0;
}

2.2.2、 http_server.h

#ifndef HTTP_SERVER_H__
#define HTTP_SERVER_H__

#include <evhttp.h>
#include <event2/thread.h>

#include <thread>

#define DEFAULT_LISTEN_PORT		( 12385 )
class CHttpServer {
public:
	
	CHttpServer();
	~CHttpServer();
	void loop();

	

	static void serverIoExec(struct evhttp_request *req, void *arg);
	
private:
	int method_POST_io_process( struct evhttp_request *req );
	int method_GET_io_process(struct evhttp_request *req);

	int pic_video_test(struct evhttp_request *_req, const std::string &strPath, const char *strParms/*参数query*/);

	void serverDispatch();			/*loop pthread process*/
	
	struct event_base *base_;
	struct evhttp 	  *http_;
	struct evhttp_bound_socket * sock_;

	bool isExit_;
	std::thread *serverloopThread_;
};
#endif 

2.3、 编译

g++ *.cpp -I ./event ./libevent*.a -lpthread

2.4、 运行结果

2.4.1、测试POST

因为没有将jsoncpp移植到项目中,所以只是简单的测试响应的基本内容
在这里插入图片描述

2.4.2 、测试GET请求

该demo请求的是二进制流
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1318600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CesiumLab地理信息基础数据处理平台 各类数据类型介绍、发布数据介绍

目录 0 引言1 CesiumLab2 数据处理模块2.1 输出格式&#xff1a;切片文件格式2.2 输入格式2.2.1 传统GIS数据2.2.2 人工模型2.2.3 BIM模型2.2.4 倾斜实景数据2.2.5 点云数据 3 发布服务功能3.1 拓展&#xff1a;其他平台发布服务功能 &#x1f64b;‍♂️ 作者&#xff1a;海码…

http状态码(一)400报错

一 400报错汇总 ① 综述 一、4xx状态码报错说明&#xff1a; 客户端行为导致的报错二、通用的4xxHTTP报错1) 4002) 4013) 4034) 4045) 405 --> 不允许方法&#xff0c;可能跨域或者nginx限制请求方法6) 4087) 4138) 419三、ngin自身定义的4xx报错495、496、497、498、4…

【JAVA-Day65】Java内部类深度解析

Java内部类深度解析 《Java内部类深度解析》摘要引言一、理解内部类1. 内部类的基本概念和语法1.1 什么是内部类&#xff1f;1.2 内部类的语法结构1.3 内部类的基本概念 2. 不同类型的内部类详解2.1 成员内部类2.2 静态内部类2.3 局部内部类2.4 匿名内部类 二、内部类与普通类的…

K - 近邻算法

1、算法介绍 KNN&#xff08;K Near Neighbor&#xff09;&#xff1a;k个最近的邻居&#xff0c;即每个样本都可以用它最接近的k个邻居来代表。KNN算法属于监督学习方式的分类算法&#xff0c;我的理解就是计算某给点到每个点的距离作为相似度的反馈。 简单来讲&#xff0c;KN…

算法-----全排列

目录 前言 代码 思路 我的其他博客 前言 全排列是一种组合数学的概念&#xff0c;它表示将一组元素按照一定顺序进行排列的所有可能情况。在计算机编程中&#xff0c;通常使用递归来实现全排列。以下是使用Java语言实现全排列的详细解释&#xff1a; 代码 public class Pe…

YOLOv8改进:ASF-YOLO助力小目标,提取多尺度特征| 2023年12月最新成果

🚀🚀🚀本文改进: ASF-YOLO一种新的特征融合网络架构,该网络由两个主要的组件网络组成,可以为小目标分割提供互补的信息:(1)SSFF模块,它结合了来自多尺度图像的全局或高级语义信息;(2)TFE模块,它可以捕获小目标的局部精细细节等 🚀🚀🚀YOLOv8改进专栏:http://…

邮件服务下载安装详细步骤、汉化、配置

Foxmail for Mac 下载地址&#xff1a;Download - hMailServer - Free open source email server for Microsoft Windows 教程地址 hMailServer安装使用教程 - 诸子流 - 博客园 (cnblogs.com) 设置密码为:dzqdb123 设置好端口 添加账号密码 (9条消息) hMailServer 配置DKIM…

软件测试找了两个月了,简历投了10万多次,找不到工作怎么办?

是行情不好吗&#xff1f;我觉得不是&#xff0c;为什么别人可以找到&#xff0c;而你找了两个月还找不到。 只能说明一个原因&#xff0c;你学的东西和企业需要有些差距。 现在&#xff0c;软件测试已经不是过去那样只会点点点就可以找到一个合适的工作。 首先因为大环境原…

人工智能导论复习资料

题型 1、简答题&#xff08;5题&#xff09; 2、设计题 3、综合题 4、论述题&#xff08;10分&#xff09; 考点 第一章 1、人工智能的定义、发展&#xff1b; 2、人工智能的学派、认知观及其间的关系&#xff1b; 3、人工智能要素及系统分类&#xff1b; 4、人工智能的研究、…

基于springboot实现的健身房管理系统

一、系统架构 前端&#xff1a;html | js | css | jquery | bootstrap 后端&#xff1a;springboot | springdata-jdbc 环境&#xff1a;jdk1.7 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 管理员-首页 03. 管理员-会员卡查询 04. 管理员-会员管理…

下午好~ 我的论文【遥感】(第一期)

写在前面&#xff1a;下午浑浑噩噩&#xff0c;泡杯茶&#xff0c;读篇论文吧 首先说明&#xff0c;时间有限没有那么精力一一回复了&#xff0c;对不起各位了TAT 文章目录 遥感Bi-Dilation-formerCNN-GNN-FusionMulti-hierarchical cross transformerCoupled CNNs 遥感 Bi-D…

Linux驱动开发学习笔记4《设备树下的LED驱动实验》

目录 一、设备树LED驱动原理 二、硬件原理图分析 三、实验程序编写 1.修改设备树文件 2.LED 灯驱动程序编写 3.编写测试APP 四、运行测试 1. 编译驱动程序和测试APP &#xff08;1&#xff09; 编译驱动程序 &#xff08;2&#xff09; 编译测试APP ​ 2.运行测试 一、…

离线无网络环境下配置Python/Anaconda环境踩过的坑

一、前言 如果你同样需要在无网络环境下安装Python环境&#xff0c;这篇博客是一个很好的参考&#xff0c;由于内网没有网络&#xff0c;因此不能使用conda install/pip install等在线下载安装方式&#xff0c;经过个人尝试&#xff0c;推荐以下两种方法。 二、离线安装python…

YOLOv3-YOLOv8的一些总结

0 写在前面 这个文档主要总结YOLO系列的创新点&#xff0c;以YOLOv3为baseline。参考(抄)了不少博客&#xff0c;就自己看看吧。有些模型的trick不感兴趣就没写进来&#xff0c;核心的都写了。 YOLO系列的网络都由四个部分组成&#xff1a;Input、Backbone、Neck、Prediction…

拖拽属性 draggable

H5 新增的属性 draggable&#xff0c;它能够给与一切的 html 元素拖动的效果。 拖拽元素 属性为 draggable"true" 的元素&#xff0c;可拖动&#xff0c;且拖动时鼠标变为禁用图标 ps: 直接写 draggable 可能无效 ondragstart 开始拖拽时触发&#xff08;按下鼠标…

单机架构到分布式架构的演变

目录 1.单机架构 2.应用数据分离架构 3.应用服务集群架构 4.读写分离 / 主从分离架构 5.引入缓存 —— 冷热分离架构 6.垂直分库 7.业务拆分 —— 微服务 8.容器化引入——容器编排架构 总结 1.单机架构 初期&#xff0c;我们需要利用我们精干的技术团队&#xff0c;快…

【算法Hot100系列】盛最多水的容器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【LeetCode】数组精选17题——双指针、滑动窗口、前缀和

目录 快慢指针&#xff1a; 1. 移动零&#xff08;简单&#xff09; 2. 复写零&#xff08;简单&#xff09; 对撞指针&#xff1a; 1. 两数之和 II - 输入有序数组&#xff08;中等&#xff09; 2. 三数之和&#xff08;中等&#xff09; 3. 有效三角形的个数&#xff…

【员工工资册】————大一期末答辩近满分作业分享

前言 大家好吖&#xff0c;欢迎来到 YY 滴项目系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C语言的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; PS&#xff1a;以下内容是部分展示&am…

全球汽车行业的数字化转型:产品和后端的渐进之旅

如何管理汽车行业的数字化转型?在我们本篇文章中了解更多有关如何设定长期目标的信息。 正在改变汽车行业的26个数字化主题 最近一篇关于汽车行业数字化转型的论文确定了26个数字技术主题&#xff08;论文详情请点击阅读原文&#xff09;&#xff0c;分为三个主要集群: 1)驾驶…