C++:http消息

前言

  最近的一些开发,需要用到http服务,大致是两种,一种是我们算法端起http服务,等到后端发送消息给算法,然后算法去解析消息,得到我们要的图像数据;第二种是,我们算法端处理完图像之后,需要将结果发送给后端,那么如果是后端发送给我们的,其实可以将处理完的结果返回即可;但也有一种情况是,需要我们算法去给后端发消息的。
  所以这其中就涉及两种情形:第一种是算法起服务,第二种是算法发送http请求。
  如果算法使用的是Python,那么起算法服务可以使用Flask这个库,如果是算法要发送http请求,那么可以使用requests这个库,也可以很方便的实现。但是如果算法是C++来写的,那么就可以考虑将算法封装成库,然后给后端调用,如果后端是python,那么可以将C++编写的算法封装成so或者dll库,然后python通过ctypes导入C++的动态库来调用,Java则是通过JNI调C++,C#也是通过调C++的动态库实现调C++的。但是,也可以类似Python一样,起算法服务,来接收http请求。这个时候就需要C++来写web服务了。这方面,其实C++也有很多web库的,但是可能用起来就没有python的库那么容易了。

一、crow

  crow是一个github上找到的开源的C++web框架,这个框架是受python下的Flask启发的,github上的介绍是:

Crow is C++ microframework for web. (inspired by Python Flask)

可见其估计功能和用法应该是和Python的Flask应该是类似的哈。该工程的结构其实也挺简单的,核心的代码都写在include中的头文件中,因此下载下来也不需要编译成库,直接include头文件即可使用,当然后期我觉得还是可以将代码的声明和定义分离,封装成库,方便调用,这样每次编译新的应用的时候都需要重新编译还是比较繁琐的。
  接下来就根据crow提供的例子来写一下,这个框架是怎么使用的。首先是要起服务,然后去监听某个端口的消息。用crow实现如下:

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "crow.h" //crow的外部头文件
#include "base64.h" //用来编码数据的base64的库
int main()
{
    crow::SimpleApp app;
    app.port(8888).multithreaded().run();

    return 0;
}

在这里插入图片描述

这样我的web服务就起来了,但是也看到这样是没有消息处理的,只是监听消息,而不对任何消息做处理,那么后端给发消息的时候就会出错。接下来就记录下个各种消息的处理。

1.1 无参数消息

  这种常见的是应该是一些我们不需要发送什么参数,只是需要从服务端获取一些信息的情况,比如服务的证据状态等。这种多数时候是一个默认的服务,常见get一个ip加端口,或者有不同的信息就给不同的字段。比如我要其一个服务,然后后端需要监控我的服务是否还健在,那么我就可以给一个默认服务或者给一个health的服务,当后端get这个地址,如果我的服务还在,就给后端返回ok等信息。实现代码也比较简单,如下:

int main()
{
    crow::SimpleApp app;

    CROW_ROUTE(app, "/")([](){
        return "Hello world!";
    });

    CROW_ROUTE(app, "/health")([](){
        return "OK";
    });
    app.port(8888).multithreaded().run();

    return 0;
}

Python端的发送消息的代码如下:

import requests
def send_health():
    url_get = "http://localhost:8888/"
    r = requests.get(url_get)
    print(r.text)
if __name__ == '__main__':
    send_health()

在这里插入图片描述

这样如果C++服务端收到消息,就会返回对应的信息给Python端。

1.2 返回json格式消息

  有时候,我们需要返回的消息会比较多,那么我们可能会指定那个字段上会有什么消息,这样得到返回的消息后,就会去解析消息,取到所需要的字段上的信息即可,不是需要的字段则可以不去管它。C++服务端的实现代码如下:

CROW_ROUTE(app, "/json")
([]{
    crow::json::wvalue x;
    x["msg"] = "Hello, World!";
    return x;
});

Python端的发送消息的代码如下:

def send_get_json():
    url_get = "http://localhost:8888/json"

    r = requests.get(url_get)
    print(r.text)
    str_json = json.loads(r.text)
    print(str_json["msg"])

在这里插入图片描述

1.3 接收json格式消息

  这种情况与1.2的类似,只不过这一次反过来,我们服务端可能会收到很多参数,但是我们只解析我们需要的字段的消息即可,所以就要接收json格式的数据,同样C++端实现如下:

    CROW_ROUTE(app, "/add_json")
        .methods("POST"_method)
    ([](const crow::request& req){
        auto x = crow::json::load(req.body);
        if (!x)
            return crow::response(400);
        int sum = x["a"].i()+x["b"].i();
        std::ostringstream os;
        os << sum;
        return crow::response{os.str()};
    });

这里可以看到,返回的消息应该是要设置为string或者crow支持的json等格式,Python端的发送消息的代码如下:

def send_num():
    url_get = "http://localhost:8888/add_json"
    data = {"a":1, "b":2}

    r = requests.post(url_get, data=json.dumps(data))
    print(r.text)
1.4 一个综合的例子

  在这个例子里:我将用Python读取一副图像,然后将图像数据通过base64编码,再把编码后的数据通过json格式数据发送给C++端,C++端接收到消息之后,会对base64数据进行解码得到图像数据,然后对图像进行一些处理,将处理后的图像通过base64进行编码,并将编码的结果返回去,Python端将返回的base64数据进行解码得到处理过后的图像。
  C++端会起算法服务,并且需要对base64数据进行编解码,然后还需要做一些图像处理的操作:

CROW_ROUTE(app, "/img")
        .methods("POST"_method)
    ([](const crow::request& req){
        auto x = crow::json::load(req.body);
        if (!x)
        {
            return crow::response(400);
        }

        std::string dst_code = x["img"].s();

        std::string dec_jpg = urlsafe_base64_decode(dst_code);
        std::vector<uchar> data(dec_jpg.begin(), dec_jpg.end());
        cv::Mat img = cv::imdecode(cv::Mat(data), 1);

        cv::Mat img_ = 255 - img;
        std::vector<uchar> buf;
        cv::imencode(".jpg", img_, buf);
        auto *enc_msg = reinterpret_cast<unsigned char*>(buf.data());
        std::string encoded = base64_encode(enc_msg, buf.size());

        return crow::response{encoded};
    });

Python需要读取图像,并把图像进行base64的编码,然后发送,对接受到的数据进行解码,并显示图像,Python端的发送消息的代码如下:

def image_to_base64(image_np):
    image = cv2.imencode('.jpg',image_np)[1]
    image_code = str(base64.urlsafe_b64encode(image))[2:-1]
    # image_code = str(base64.b64encode(image))[2:-1]

    return image_code

def base64_to_image(base64_code):
    # base64解码
    # img_data = base64.b64decode(base64_code)
    img_data = base64.urlsafe_b64decode(base64_code)
    # 转换为np数组
    img_array = np.fromstring(img_data, np.uint8)
    # 转换成opencv可用格式
    img = cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)

def send_img():
    url_get = "http://localhost:8888/img"

    mat = cv2.imread("./cat.jpg")

    data_base64 = image_to_base64(mat)
    data = {"img": data_base64}

    r = requests.post(url_get, data=json.dumps(data))
    # print(r.text)

    img = base64_to_image(r.text)
    cv2.imshow("img", img)
    cv2.waitKey(0)

以上是我目前需要用到的功能,后期如果需要用到更多的功能,还会继续开发这个库,不过目前基本满足了我的需要了。

cpp-httplib

  待补充…

耕人扶耒语林丘,花外时时落一鸥。
欲验春来多少雨,野塘漫水可回舟。
– 宋代·周邦彦 《春雨》

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
HTTP(Hypertext Transfer Protocol)是一种用于在网络中传输超文本的协议。HTTP协议解析是指对传输的HTTP数据进行分析和处理的过程。 HTTP协议是基于客户端-服务器模型的,客户端发送请求消息给服务器,服务器会返回相应的响应消息。在解析HTTP协议时,主要涉及下面几个方面: 1. 解析请求:客户端发送的请求消息包含请求行、请求头和请求体三个部分。解析请求就是从收到的数据中解析出这些部分的内容,并进行相应的处理。其中,请求行包含了请求的方法(如GET、POST等)、URL和HTTP版本等信息;请求头包含了附加的请求信息,如浏览器类型、文档类型等;而请求体则是可选的,一般用于传递POST请求的参数。 2. 解析响应:服务器返回的响应消息也包含响应行、响应头和响应体三个部分。解析响应就是从收到的数据中解析出这些部分的内容,并进行相应的处理。响应行包含了HTTP状态码(如200表示成功、404表示找不到等)和HTTP版本;响应头包含了附加的响应信息,如服务器类型、返回的数据类型等;响应体则是实际返回的数据。 3. 处理状态码:HTTP协议定义了各种状态码,用于表示请求的处理结果。在解析HTTP协议时,需要根据接收到的状态码进行相应的处理,如根据200判断请求成功,根据404判断页面不存在等。 4. 保持连接:HTTP协议支持保持连接,在解析HTTP协议时,需要根据请求头是否包含Connection字段来判断是否需要保持连接。如果需要保持连接,可以继续使用原来的TCP连接发送下一个请求。 总之,HTTP协议解析是通过解析请求和响应消息,处理状态码和保持连接等方式对HTTP协议的传输数据进行处理和分析的过程。这样就能够正确地读取和理解HTTP传输的数据,实现客户端与服务器的通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值