libevent服务GET/POST的简单使用

目录

  • 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.mfbz.cn/a/245901.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《算法通关村——透彻理解动态规划》

《算法通关村——透彻理解动态规划》 62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff…

Matlab示例-Examine 16-QAM Using MATLAB学习笔记

​工作之余学习16-QAM 写在前面 网上看到许多示例&#xff0c;但一般都比较难以跑通。所以&#xff0c;还是老方法&#xff0c;先将matlab自带的例子研究下。 Examine 16-QAM Using MATLAB Examine 16-QAM Using MATLAB 或者&#xff0c;在matlab中&#xff0c;键入&#x…

Re9 Attention is all you need

变形金刚&#xff0c;启动&#xff01; Abstract 主流序列转录模型基于复杂的循环神经网络和卷积神经网络&#xff0c;包括一个encoder和decoder&#xff0c;同时在这之中使用一个叫注意力机制attention的东西本文提出了一个简单的网络架构&#xff0c;仅仅使用注意力机制&am…

【论文阅读】O’Reach: Even Faster Reachability in Large Graphs

Hanauer K, Schulz C, Trummer J. O’reach: Even faster reachability in large graphs[J]. ACM Journal of Experimental Algorithmics, 2022, 27: 1-27. Abstract 计算机科学中最基本的问题之一是可达性问题&#xff1a;给定一个有向图和两个顶点s和t&#xff0c;s可以通过…

(1)Linux的 安装与用户的创建

前言 本章正式开始Linux的学习 如果关于Linux环境搭配有问题的朋友 可以阅读此文章:Linux环境搭建 一&#xff0c;浅用一下吧 —— Hello, Linux! 我们现在已经登陆上了&#xff0c;我们当然可以用它来做很多事。 我们来用它写一个 "Hello, Linux!" &#xff0c;来…

Layui继续学习

1、简单评论区代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>社区评论区</title> <link rel"stylesheet" href"https://cdn.staticfile.org/layui/2.6.8/css/…

关于“Python”的核心知识点整理大全20

目录 ​编辑 9.2 使用类和实例 9.2.1 Car 类 下面来编写一个表示汽车的类&#xff0c;它存储了有关汽车的信息&#xff0c;还有一个汇总这些信息的方法&#xff1a; car.py 9.2.2 给属性指定默认值 9.2.3 修改属性的值 1. 直接修改属性的值 2. 通过方法修改属性的值 3.…

记录Oracle Exadata X8M-2 存储服务器告警灯亮的处理过程(/SYS/MB/P0PCIE7)

文章目录 概要调查流程处理方式&#xff1a; 概要 现场服务器告警灯亮&#xff0c;其他服务器正常&#xff0c;磁盘灯正常&#xff0c;所以从整体来看应是内部部件抛出的异常问题&#xff0c;需要登录机器确认&#xff1a; 调查流程 通过ILOM web界面查看服务器状态进行信息…

基于轻量级GhostNet模型开发构建工业生产制造场景下滚珠丝杠传动表面缺陷图像识别系统

轻量级识别模型在我们前面的博文中已经有过很多实践了&#xff0c;感兴趣的话可以自行移步阅读&#xff1a; 《移动端轻量级模型开发谁更胜一筹&#xff0c;efficientnet、mobilenetv2、mobilenetv3、ghostnet、mnasnet、shufflenetv2驾驶危险行为识别模型对比开发测试》 《基…

低代码与自动化:加速软件开发的新趋势

低代码与自动化技术正在逐渐改变软件开发的面貌。随着科技的不断发展&#xff0c;传统的编程方式已经不再是唯一的选择。低代码和自动化技术正在为开发者提供更高效、更灵活的开发环境&#xff0c;使得软件开发变得更加简单、快速和高效。 低代码和自动化技术正在逐渐改变软件开…

el-table自定义表格数据

如上所示&#xff1a; 表格内的数据是&#xff1a;当前班级所在名次段的人数 / 当前班级1至n名的累计人数 5/12 也就是 5/75 需要变更为&#xff1a; 截至到当前名次段总人数&#xff08;上次考试&#xff09; / 截至到当前名次段总人数&#xff08;本次考试&#xff09…

使用VBA快速统计词组词频(多单词组合)(2/2)

实例需求&#xff1a;产品清单如A列所示&#xff0c;现在如下统计多单词组合词组词频。 在上一篇博客中《使用VBA快速统计词组词频(多单词组合)&#xff08;1/2&#xff09;》讲解了如何实现双词的词频统计。 本文将讲解如何实现3词的词频统计&#xff0c;掌握实现方法之后&a…

android studio 快捷输入模板提示

在Android开发中&#xff0c;我们经常会遇到一些重复性的代码&#xff0c;例如创建一个新的Activity、定义一个Getter方法等。为了提高开发效率&#xff0c;Android Studio提供了Live Templates功能&#xff0c;可以通过简化输入来快速生成这些重复性代码。 按下图提示设置&am…

做博客网站需要什么配置的服务器?

​  利用搭建博客网站&#xff0c;来分享生活、知识和经验&#xff0c;是很多个人站长乐意做的事情。但&#xff0c;对于互联网行业的新人来说&#xff0c;或许不知道搭建个人博客网站的配置如何选择&#xff0c;本文针对这一点&#xff0c;从地域、服务器类型、配置参数等方…

使用动画曲线编辑器打造炫酷的3D可视化ACE

前言 在制作3D可视化看板时&#xff0c;除了精细的模型结构外&#xff0c;炫酷的动画效果也是必不可少的。无论是复杂的还是简单的动画效果&#xff0c;要实现100%的自然平滑都是具有挑战性的工作。这涉及到物理引擎的计算和对动画效果的数学建模分析。一般来说&#xff0c;只…

Tekton 基于 cronjob 触发流水线

Tekton 基于 cronjob 触发流水线 Tekton EventListener 在8080端口监听事件&#xff0c;kubernetes 原生 cronjob 定时通过curl 命令向 EventListener 发送事件请求&#xff0c;触发tekton流水线执行&#xff0c;实现定时运行tekton pipeline任务。 前置要求&#xff1a; kub…

大数据技术13:HBase分布式列式数据库

前言&#xff1a;2007年Powerset的工作人员&#xff0c;通过google的论文开发出了BigTable的java版本&#xff0c;即HBASE。2008年HBASE贡献给了Apache。HBase 需要依赖 JDK 环境。 一、Hadoop的局限 HBase 是一个构建在 Hadoop 文件系统之上的面向列的数据库管理系统。 要想…

【开源Mongdb驱动】SpringBoot+Mybatis+Mongdb融合使用教程

#【开源Mongdb驱动】SpringBootMybatisMongdb无缝融合使用教程 介绍 本文介绍一款基于JAVA开源的mongodb jdbc驱动为基础的无缝与springbootmybatis融合使用案例 mongodb JDBC 使用案例 https://blog.csdn.net/gongbing798930123/article/details/135002530 《基于开源的JA…

网站使用CDN后无法获取用户真实IP的解决方法

宝塔或Nginx环境 如果你使用的宝塔或Nginx&#xff0c;可以在宝塔面板或Nginx中&#xff0c;找到配置文件增加如下代码后&#xff0c;重载配置或者重启 Nginx 即可&#xff1a; #CDN获取真实ip set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; PHP语言函数方法…

Spring Boot+FreeMarker=打造高效Web应用

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Spring BootFreeMarker的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. FreeMarker是什么 二…
最新文章