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前端通信,比较常用的使用POST和GET方式带出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 emitUTF8std::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的请求APIif(!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-8std::string strRespJsonBody("这里是协议内相关Json");evbuffer_add_printf(pRespbuffer, "%s", strRespJsonBody.c_str()); //向evbuffer中增加messageevhttp_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请求的是二进制流
相关文章:
libevent服务GET/POST的简单使用
目录 1、前言2、测试demo2.1、目录结构2.2、 测试源码2.2.1、http_server.cpp2.2.2、 http_server.h 2.3、 编译2.4、 运行结果2.4.1、测试POST2.4.2 、测试GET请求 1、前言 项目开发中经常需要使用到私有协议和Qt,Android等GUI前端通信,比较常用的使用POST和GET方式…...
MySQL 系列:注意 ORDER 和 LIMIT 联合使用的陷阱
文章目录 前言背后的原因ORDER BY 排序列存在相同值时返回顺序是不固定的LIMIT 和 ORDER BY 联合使用时的行为ORDER BY 或 GROUP BY 和 LIMIT 联合使用优化器默认使用有序索引 如何解决其它说明个人简介 前言 不知道大家在在分页查询中有没有遇到过这个问题,分页查…...
通过实例理解OAuth2授权
在之前的《通过实例理解Go Web身份认证的几种方式[1]》和《通过实例理解Web应用授权的几种方式[2]》两篇文章中,我们对Web应用身份认证(AuthN)和授权(AuthZ)的几种方式做了介绍并配以实例增强理解。 在现实世界中,还有一大类的认证与授权是在前面的文章中…...
MATLAB2022安装下载教程
安装包需从夸克网盘自取: 链接:https://pan.quark.cn/s/373ffc9213a1 提取码:N7PW 1.将安装包解压 2.以管理员的身份运行文件夹中的setup文件 3.点击高级选项--->我有文件安装密钥 4. 选择【是】,进入下一步 5.输入密钥 0532…...
从零开始搭建Go语言开发环境
https://www.liwenzhou.com/posts/Go/install_go_dev/ “go 命令现在默认在模块感知模式下构建包,即使没有 go.mod 存在也是如此。 “您可以将 GO111MODULE 设置为 auto,仅当当前目录或任何父目录中存在 go.mod 文件时,才能启用模块感知模式…...
vite+vue3+ts+tsx+ant-design-vue项目框架搭建
参与公司项目开发一段时间了,项目用到了很多新的技术(vite,vue3,ts等等),但是框架都是别人搭好的,然后就想说如果是自己的话,会从零搭建一个吗,于是就有了这篇文章。 目录 一、涉及到的相关依…...
【5G PHY】5G小区类型、小区组和小区节点的概念介绍
博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…...
创建个人网站(一)从零开始配置环境,搭建项目
目录 前言配置环境前端后端遇到的问题1.安装了nvm和node,vscode没反应2.安装完脚手架之后vue指令不存在 vscode插件(以后遇到好的会添进去) 前言 从刚开始学前端的html直到现在前后端都有在开发,我一直都有一个想法,就…...
fripside - promise lrc
[ti:promise] [ed:2] [rt:20] [ml:0|0] [00:05.172]words:Satoshi Yaginuma, Shinichiro Yamashita [00:09.664]music&arrangement:Satoshi Yaginuma, Shigetoshi Yamada [00:14.565]PCゲーム「ENGAGE LINKS」 (Alcot) エンディングテーマ [00:20.000] [00:46.442]朝の陽射…...
网络连接和协议
网络连接是通过一系列协议来实现的,其中TCP/IP协议和HTTP协议是其中两个关键的协议。 1. **TCP/IP协议:** - TCP/IP(Transmission Control Protocol/Internet Protocol)是一组用于在互联网上传输数据的协议。它是一个层次化的…...
MySQL数据库,表的增量备份与恢复
1. 从物理与逻辑的角度 数据库备份可以分为物理备份和逻辑备份。物理备份是对数据库操作系统的物理文件(如数据 文件,日志文件等)的备份。这种类型的备份适用于在出现问题时需要快速恢复的大型重要数据库。 物理备份又可以分为冷备份…...
13.Spring 整合 Kafka + 发送系统通知 + 显示系统通知
目录 1.Spring 整合 Kafka 2.发送系统通知 2.1 封装事件对象 2.2 开发事件的生产者和消费者 2.3 触发事件:在评论、点赞、关注后通知编辑 3.显示系统通知 3.1 通知列表 3.1.1 数据访问层 3.1.2 业务层 3.1.3 表现层 3.2 开发通知详情 3.2.1 开发数据…...
windows 服务器 怎么部署python 程序
一、要在 Windows 服务器上部署 Python 程序,您需要遵循以下步骤: 安装 Python:首先,在 Windows 服务器上安装 Python。您可以从官方网站(https://www.python.org/downloads/windows/)下载最新的 Python 安…...
Chapter 7 - 2. Congestion Management in Ethernet Storage Networks以太网存储网络的拥塞管理
Location of Ingress No-Drop Queues入口无损队列的位置 Ingress queues for no-drop traffic are maintained by all the ports in a lossless Ethernet network. For the sake of simplicity, Figure 7-1 shows ingress no-drop queue(s) only at one location, but in real…...
深入理解前端项目中的 package.json
在前端开发中,package.json 是一个很重要的文件,它在Node.js和前端项目中扮演着重要的角色。这个文件用于存储项目的元数据以及管理项目的依赖关系。 package.json 文件是每个Node.js项目和许多前端项目的核心。它不仅定义了项目的基本属性,…...
4-Docker命令之docker build
1.docker build介绍 docker build命令是用来使用Dockerfile文件创建镜像 2.docker build用法 docker build [参数] PATH | URL | - [root@centos79 ~]# docker build --helpUsage: docker buildx build [OPTIONS] PATH | URL | -Start a buildAliases:docker buildx build…...
Hdfs java API
1.在主机上启动hadoop sbin/start-all.sh 这里有一个小窍门,可以在本机上打开8088端口查看三台机器的连接状态,以及可以打开50070端口,查看hdfs文件状况。以我的主虚拟机为例,ip地址为192.168.198.200,所以可以采用下…...
大数据Doris(三十七):索引和Rollup基本概念和案例演示
文章目录 索引和Rollup基本概念和案例演示 一、基本概念 二、 案例演示...
2019年第八届数学建模国际赛小美赛B题数据中心冷出风口的设计解题全过程文档及程序
2019年第八届数学建模国际赛小美赛 B题 数据中心冷出风口的设计 原题再现: 这是数据中心空调设计面临的一个问题。在一些数据中心,计算机机柜是开放的,在一个房间里排列成三到四排。冷却后的空气通过主管进入房间,并分为三到四个…...
mmpose 使用笔记
目录 自己整理的可以跑通的代码: 图片demo: 检测加关键点 自己整理的可以跑通的代码: 最强姿态模型 mmpose 使用实例-CSDN博客 图片demo: python demo/image_demo.py \tests/data/coco/000000000785.jpg \configs/body_2d_k…...
<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的区别
<url-pattern>/</url-pattern> servlet的url-pattern设置为/时, 它仅替换servlet容器的默认内置servlet,用于处理所有与其他注册的servlet不匹配的请求。直白点说就是,所有静态资源(js,css,ima…...
Spring IoCDI
文章目录 一、Spring、Spring boot、Spring MVC之间的区别1. Spring 是什么2. 区别概述 一、Spring、Spring boot、Spring MVC之间的区别 1. Spring 是什么 Spring 是包含了众多工具方法的 IoC 容器 (1)容器 容器是用来容纳某种物品的基本装置…...
vue使用el-tag完成添加标签操作
需求:做一个添加标签的功能,点击添加后输入内容后回车可以添加,并且标签可以删除 1.效果 2.主要代码讲解 鼠标按下后触发handleLabel函数,根据回车的keycode判断用户是不是按下的回车键,回车键键值为13,用…...
ACM-MM2023 DITN详解:一个部署友好的超分Transformer
目录 1. Introduction2. Method2.1. Overview2.2. UFONE2.3 真实场景下的部署优化 3. 结果 Paper: Unfolding Once is Enough: A Deployment-Friendly Transformer Unit for Super-Resolution Code: https://github.com/yongliuy/DITN 1. Introduction CNN做超分的缺点 由于卷…...
STM32超声波——HC_SR04
文章目录 一.超声波图片二.时序图三.超声波流程四.单位换算五.取余计算六.换算距离七.超声波代码 一.超声波图片 测量距离:2cm——400cm 二.时序图 (1).以下时序图要先提供一个至少10us的脉冲触发信号,告诉单片机我准备好了,然后该超声波…...
[Excel] vlookup函数
VLOOKUP用法 VLOOKUP(lookup_value, table_array, col_index_num, [range_lookup])其中: lookup_value是你要查找的值table_array是你要在其中进行查找的表格区域col_index_num是你要返回的在table_array中列索引号range_lookup是一个可选参数,用于指定…...
Python入门第5篇(爬虫相关)
目录 爬虫初步说明 html相关基础 urllib之读取网页内容 http相关基础 requests之webapi调用 爬虫初步说明 爬虫,一句话来说,即模拟浏览器爬取一些内容,如自动下载音乐、电影、图片这种的 具体可能是直接访问网页进行解析,也…...
单元测试二(实验)-云计算2023.12-云南农业大学
1、实践系列课《深入浅出Docker应用》 https://developeraliyun.com/adc/scenarioSeries/713c370e605e4f1fa7be903b80a53556?spma2c6h.27088027.devcloud-scenarioSeriesList.13.5bb75b8aZHOM2w 容器镜像的制作实验要求 创建Dockerfile文件: FROM ubuntu:latest WORKDIR data…...
Axure动态面板的使用以及示例分享
目录 一. 什么是动态面板 二. 动态面板教程——以轮播图为例 2.1 创建动态面板 2.2 动态面板自适应大小 2.3 重复状态,将图片导入 2.4 添加交互事件——图片切换 2.5 效果展示 三. 多方式登录示例展示 四. 后台主界面左侧菜单栏示例展示 一. 什么是动态面板…...
容斥原理的并
文章目录 简介AcWing 890. 能被整除的数思路解析CODE 简介 推荐题解:https://www.acwing.com/solution/content/126553/ 画了图,清晰易懂,懒得打字了。 总之就是以下公式: S S 1 S 2 S 3 − S 1 ∩ S 2 − S 1 ∩ S 3 − S 2 …...
wordpress 地址插件/seopeixun
1、为什么使用em em也是css中的一种单位,和px类似。很多人会疑惑为什么有了px之后还要使用em,而且em使用起来相对于px来讲比较麻烦。 em主要是应用于弹性布局,下面给出一个小栗子说明em的强大之处 <!DOCTYPE html> <html lang"…...
厦门最早做网站的公司/域名注册后怎么使用
Spring的自动装配,也就是定义bean的时候让spring自动帮你匹配到所需的bean,而不需要我们自己指定了。例如:User实体类里面有一个属性role1234567public class User {private int id;private String username;private String password;private…...
景观设计公司利润/谷歌优化是什么意思
ftp服务很重要,这里介绍ftp在linux上不连接mysql数据库的搭建方法,ftp也可以连接mysql,有时间再生成文档。先说明ftp的基本原理:FTP �File Transfer Protocol 文件传输协议。能够在网络上提供文件传输服务,…...
湛江网站建设外包/seo专业实战培训
摘要:虚拟机Apache设置很多用户都遇到过,具体如何进行虚拟机Apache设置?怎样才能让虚拟机Apache设置达到最简单,最优化?本文为您讲解。Apache虚拟机设置有两种方法: 基于主机名的虚拟主机(一个IP地址&#…...
网站开发需求ppt/百度搜索优化关键词排名
其实在淘宝上面也有很多卖家都想要去打造属于自己店铺的爆款商品。 但是又不知道淘宝做爆款商品的目的是什么,也不知道爆款商品到底应该要怎么做,我马上就来给各位卖家介绍。 我们打造爆款是为了让我们通过爆款赚钱,通过爆款引来的流量带动其…...
手机wordpress查看加密文章/网站开发建设步骤
Python中使用import语句来导入一个模块(module),或者用来导入一个包(package),模块的实质就是一个*.py文件,实现了一定逻辑功能,包含了变量、函数、类等代码块,包的实质就是一个项目工程,里面有很多*.py文件…...