当前位置:首页 » 《休闲阅读》 » 正文

cpp-http 库的使用_三十的南瓜饭的博客

28 人参与  2021年12月31日 15:58  分类 : 《休闲阅读》  评论

点击全文阅读


文章目录

    • 前言
    • `cpp-http` 库简介
    • `cpp-http` 库使用介绍
      • http 客户端搭建步骤
      • http 服务端搭建步骤
    • `cpp-http` 库示例
      • 服务端实现
      • 客户端实现
  • 参考资料

前言

最近在做的一个项目需要使用到 HTTP 协议,在网上查了很久,也结合了之前学长做的项目,发现 cpp-http 库使用挺多的,所以就边学边做笔记,顺便分享出来(我觉得知识之所以叫知识,就是因为它能被记录并能被传播,为人所知,为人所识)。

我准备把这个学习记录做成一个系列文章,这个系列里面,我会介绍从 HTTP 协议诞生到目前的一些大概情况,然后会简单介绍一下目前 C/C++ 下面用的比较广泛的 HTTP 库,之后就是讲解 cpp-http 库的简单使用、 cpp-http 库的实现,最后如果时间允许的话可以自己手码一个 C 语言的 http 用来作总结。

反正 flag 在这里先立下了,这篇文章是这个系列的第一篇,但是并不是按顺序来的第一篇,这里讲的是 cpp-http 库的简单使用,按顺序来看的话应该是系列里面的第三篇或者第二篇。如果大家目前对 HTTP 协议基础知识有需求的话还请移步其他博主的文章,之后我也会陆续把各个模块补上(下一篇可能是 cpp-http 库的实现部分),敬请大家期待。

另:本人目前是大学生,新人一枚,文章之中难免会有纰漏,还请大家多多包涵,不吝赐教。

cpp-http 库简介

  1. cpp-http 库是什么?
    cpp-http 由是一位国外程序员 yhirose 在 github 上面开源的一个 C++ 项目,同时这个项目得到了世界各地程序员的支持,目前包括原作者在内共有 104 位贡献者,拥有 5.7k Star 和 1.2k Fork,是目前使用较为广泛的一个 C++ http库之一。

  2. cpp-http 项目地址
    https://github.com/yhirose/cpp-httplib
    如果网络不好不能访问 github 的话,这里是国内一位程序员搬运到 gitee 上面的项目,内容都是一样的:
    https://gitee.com/zhangkt1995/cpp-httplib?_from=gitee_search

  3. 关于它的简介,这里引用原作者的话:

    A C++11 single-file header-only cross platform HTTP/HTTPS library.

    It’s extremely easy to setup. Just include the httplib.h file in your code!

    NOTE: This is a multi-threaded ‘blocking’ HTTP library. If you are looking for a ‘non-blocking’ library, this is not the one that you want.

    翻译过来就是:

    一个只有头文件的跨平台 HTTP/HTTPS 库。

    简单易用,只需要包含头文件 httplib,h 即可。

    注意:这个库是一个多线程阻塞式 Http 库,如果您需要的是一个非阻塞式的库,这个库并不适合您。

cpp-http 库使用介绍

网上大多数教程都只介绍了使用 cpp-http 库的 GET 请求使用,没有 POST 请求的(其实两者使用一模一样),在这里我也加上了 POST 请求的部分。

http 客户端搭建步骤

  1. 组织http协议格式的请求数据
  2. 搭建tcp客户端
  3. 发送组织好的http请求数据
  4. 等待服务端响应,接收响应数据
  5. 对响应数据的解析

http 服务端搭建步骤

  1. 搭建tcp服务端
  2. 等待接收客户端发送的数据
  3. 按照 http 协议格式,对数据进行解析(格式按照: 请求方法 URL 协议版本\r\n 头部\r\n 正文)
  4. 根据请求的资源路径以及查询字符串以及正文,进行业务处理
  5. 组织http协议格式的响应,返回给客户端(协议版本 状态码 描述\r\n 头部)

cpp-http 库示例

这里我们先用个 demo 来看看 cpp-http 库怎么使用:

首先先建立工程,目录如下:

▶ tree ../http -L 1 
../http
├── client.cpp	# 在这里编辑客户端的代码
├── httplib.h	# 这是 cpp-http 库的头文件,server和client都需要包含它
└── server.cpp # 在这里编辑服务端的代码

0 directories, 5 files

其中 httplib.h 就是 cpp-http 库的所有内容了,就是这一个头文件;server.cpp 是我们自己的服务端程序, client.cpp 是我们自己的客户端程序。

服务端实现

  1. 代码。相关的解释都在注释里面
#include <iostream>
#include "httplib.h"

using Request = httplib::Request;
using Response = httplib::Response;
using Server = httplib::Server;
using Params = httplib::Params;

// get 请求中对 "/go" 的处理
void get_go(const Request& req, Response& res)
{
    // 设置 "/go" 请求返回的内容
    res.set_content("<html><h1>I'm the king of the world!</h1></html>", "text/html");

    std::cout << "Received a request of get [go]." << std::endl;
}

int main(int argc, char const *argv[])
{
    // 搭建服务端
    Server srv;

    // 这里注册用于处理 get 请求的函数,当收到对应的get请求时,程序会执行对应的函数
    srv.Get("/go", get_go); // 可能相比 lambda 表达式,刚从 C 语言转过来的同学更熟悉这种形式,这个get调用方式也更简介易懂

    // 这里注册的处理函数是 C++ 的 lambda 表达式,直接看成传入了一个指针就行了
    srv.Get("/hi", [&](const Request& req, Response& res){
        // 设置 get "hi" 请求返回的内容
        res.set_content("<html><h1>Hello world!</h1></html>", "text/html");

        std::cout << "Received a request of get [hi]." << std::endl;
    });
    
    srv.Get("/link", [&](const Request& req, Response& res){
        res.set_content("<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>", "text/html");

        std::cout << "Received a request of get [link]." << std::endl;
    });

    // POST 请求处理
    srv.Post("/get_info", [&](const Request& req, Response& res) {
        res.set_content("<html><h1>Go ahead!</h1></html>", "text/html");

        std::cout << "Received a request of POST [get_info]." << std::endl;
    });

    // 绑定端口,启动监听
    srv.listen("0.0.0.0", 12345);
    
    return 0;
}

这里大家可能有三个疑问:

  • Server::Get()Server::Post() 注册函数的实现机制,收到请到 GET 请求后是怎么执行对应函数的
  • 使用 Server::listen() 启动端口的实现机制
  • lambda 表达式

其中前两点我会在后面解释,关于lambda表达式的部分可能之后会出相应的文章来介绍,在此之前还请各位移步其他关于 lambda 的文章进行学习。

  1. 编译
    cpp-http 库编译时需要使用线程库 pthread
    编译时使用 g++ 直接编译,使用 gcc 编译会报错(毕竟 gcc 是为 C 设计的)

编译时使用命令:

g++ ./server.cpp -lpthread -o sever.out
  1. 执行
    执行服务端程序:
./server.out
  1. 验证服务端:
  • 可以通过 curl 来查看服务端返回的数据
# 示例如下
$ curl http://ip:port/source 
# 这里的 ip 是服务端运行所在电脑的ip,可以通过 `ip -a` 来查看
# port 就是我们在服务端里面指定监听的端口
# source 是通过 http 请求的资源,在这里就是 /hi /link /go 那三个。

在这里插入图片描述
最后一行 使用 curl http://0.0.0.0:12345/get_info 时没有返回,并且服务器端也没有接收到数据,说明 curl 直接发送 /get_info 并不能用于提交 POST 请求,怎么使用 curl 提交 POST 请求等我之后有时间了再看看。

curl http://0.0.0.0:12345/hi  # 这里是请求 /link 资源需要的命令
	<html><h1>Hello world!</h1></html>% # 这里是服务器回应的数据curl http://0.0.0.0:12345/link
	<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>%

	▶ curl http://0.0.0.0:12345/go
	<html><h1>I'm the king of the world!</h1></html>%
  
  ▶ curl http://0.0.0.0:12345/get_info
  • 也可以通过浏览器来查看数据:

通过在浏览器地址栏输入相应的地址来验证 http 服务端,直接在浏览器地址栏填入链接就好了:
例如我在浏览器输入如下地址

http://http://0.0.0.0:12345/hi

结果如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HlVbtJ5-1632225570442)(:/7d334fd2bb5546a6ae90e6e14f0938a5)]

  • 如果一切正常的话,服务端的输出是这样:

▶ ./server.out
Received a request of get [link].
Received a request of get [link].
Received a request of get [hi].
Received a request of get [link].
Received a request of get [link].
Received a request of get [go].
Received a request of get [hi].

客户端实现

  1. 代码
#include <iostream>
#include <string>
#include "httplib.h"

using Client = httplib::Client;
using string = std::string;

int main(int argc, char const *argv[])
{
    if (argc < 3) {
        std::cout << "Please input server ip and port" << std::endl;

        return 0;
    }

    string source; // 用于存储资源名称

    // 创建客户端
    // argv[1] 是从命令行传入的 ip
    // argv[2] 是从命令行传入的 port
    Client cli(argv[1], atoi(argv[2]));

    // 这里是一个死循环,用于选择需要读取的资源
    while (true) {
        std::cout << "Please input the source you want" 
                  << "(Or use <CTRL + Z> to exit):" 
                  << std::endl;

        // 从命令行获取下一步需要获取的资源名称
        std::getline(std::cin, source, '\n');
        // std::cout << source << std::endl;

        // GET、POST 请求的返回值
        std::shared_ptr<httplib::Response> res;

        if (source == "/get_info") {
            // POST 请求
            res = cli.Post(source.c_str()); 
        } else {
            // GET 请求
            res = cli.Get(source.c_str());
        }
        
        if (res) {
            if (res->status == 200) { // 获取对应资源成功,输出获取到的信息
                std::cout << "Recved response from server: \n\r"
                          << res->body 
                          << "\n\r" << std::endl;
            } else{ // 获取资源失败,输出 http 状态码
                std::cout << "Request error: " << res->status 
                          << "\n\r" << std::endl;
            }
        } else { // 发送失败(多半是配置问题)
            std::cout << "Request GET failed.\n\r" << std::endl;
        }

        sleep(1); // 线程休眠
    }
    
    return 0;
}
  1. 编译
  • 编译命令和 编译 server.cpp 是一样的,不过参数要改成 client.cpp
g++ ./client.cpp -lpthread -o client.out
  • 编译完成后的目录:
▶ tree -L 1 ../http 
../http
├── client.cpp
├── client.out
├── httplib.h
├── server
├── server.cpp
└── server.out

0 directories, 6 files
  1. 执行
  • 执行服务端和客户端程序:
./server.out
  • 执行客户端程序:
▶ ./client.out 0.0.0.0 12345
Please input the source you want(Or use <CTRL + Z> to exit):
/go
Recved response from server: 
<html><h1>I'm the king of the world!</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
/link
Recved response from server: 
<html><h1 href=https://baike.baidu.com/item/%E8%A5%BF%E5%8D%8E%E5%A4%A7%E5%AD%A6%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B6%B3%E7%90%83%E5%8D%8F%E4%BC%9A/22274030>soccer robot</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
/hi
Recved response from server: 
<html><h1>Hello world!</h1></html>

Please input the source you want(Or use <CTRL + Z> to exit):
  • 程序执行结果:
    在这里插入图片描述

参考资料

  1. 如何用chrome浏览器发送POST请求:https://www.hm1006.cn/archives/chromepost
  2. 【项目】cpp-httplib库的原理:https://blog.csdn.net/weixin_43939593/article/details/104263043
  3. 推荐一个比较好用的c++版本http协议库-cpp-httplib:https://blog.csdn.net/wuquan_1230/article/details/117690607

点击全文阅读


本文链接:http://zhangshiyu.com/post/32464.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1