基于asio的httpclient实现

基于Asio实现一个简易的httpclient

Asio是C++的一个高性能网络编程库,提供了跨平台的网络和底层I/O编程接口,包括tcp,udp等sockets通信,以及异步编程模型。它的设计目标是为C++开发者提供一种简单、直接的方式来处理网络通信和并行I/O操作,同时保持高效和灵活性。

知识点

  • 使用asio::io_context ioctx;作为整个网络IO和回调的上下文
  • 使用std::thread processor;作为ioctx的执行线程,只需要在线程函数里执行ioctx.run()即可触发io事件循环工作
  • 使用asio::executor_work_guard<asio::io_context::executor_type> work;保证ioctx不会因为没有执行任务而结束,导致线程退出
  • 使用 asio::ip::tcp::resolver resolver_;进行dns域名解析
  • 使用std::promise/std::future进行异步任务同步等待,类似于javascript的async/await

源码

https://github.com/samxfb/cpp-httpclient

编译输出cpp-httpclient

Usage:
./cpp-httpclient [ip] [port] [method:GET/POST...] [url/path]
./cpp-httpclient --host [host] [method:GET/POST...] [url/path]

测试用例

1、借助在线的http服务(https://httpbin.org/

./cpp-httpclient --host httpbin.org GET /get

connect httpbin.org [ip 184.73.216.86, port 80]

RESULT: HTTP/1.1 200  OK
response message:
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-65ab4f91-7370ba8a2d5dee213fb955d6"
  }, 
  "origin": "218.108.104.131", 
  "url": "http://httpbin.org/get"
}

2、自己搭建一个简易的静态http服务器

  • 基于apache搭建

详见(Linux系统下Web文件系统搭建

  • 使用python自带的http.server模块

python3 -m http.server 9000, 端口号为9000

  • 基于Node.js的轻量级静态HTTP服务器http-server

安装:npm install -g http-server
运行:http-server --port 9000

以下测试启动node.js http-server进行:

(base) sam@SamdeMacBook-Pro:~/Desktop/test/cpp-httpclient$ http-server --port 9000
Starting up http-server, serving ./

http-server version: 14.1.1

http-server settings: 
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none

Available on:
  http://127.0.0.1:9000
  http://10.18.146.230:9000
Hit CTRL-C to stop the server

http客户端请求

./cpp-httpclient 127.0.0.1 9000 GET /build.sh

RESULT: HTTP/1.1 200  OK
response message:
#!/bin/bash

g++ -std=c++11 -I. -I./thirdparty/asio/asio/include -pthread -o cpp-httpclient test.cpp
  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用asio实现的websocket客户端的示例代码: ```cpp #include <iostream> #include <asio.hpp> #include <string> using asio::ip::tcp; class WebsocketClient { public: WebsocketClient(asio::io_context& io_context, const std::string& server, const std::string& path) : m_resolver(io_context), m_socket(io_context), m_server(server), m_path(path) { } void Connect() { tcp::resolver::query query(m_server, "80"); m_resolver.async_resolve(query, [this](const asio::error_code& error, tcp::resolver::iterator endpoint_iterator) { if (!error) { asio::async_connect(m_socket, endpoint_iterator, [this](const asio::error_code& error, tcp::endpoint) { if (!error) { // 发送HTTP请求 asio::streambuf request; std::ostream request_stream(&request); request_stream << "GET " << m_path << " HTTP/1.1\r\n"; request_stream << "Host: " << m_server << "\r\n"; request_stream << "Upgrade: websocket\r\n"; request_stream << "Connection: Upgrade\r\n"; request_stream << "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"; request_stream << "Sec-WebSocket-Version: 13\r\n\r\n"; asio::async_write(m_socket, request, [this](const asio::error_code& error, std::size_t) { if (!error) { // 读取HTTP响应 asio::async_read_until(m_socket, m_response, "\r\n\r\n", [this](const asio::error_code& error, std::size_t) { if (!error) { std::istream response_stream(&m_response); std::string http_version; response_stream >> http_version; unsigned int status_code; response_stream >> status_code; std::string status_message; std::getline(response_stream, status_message); if (http_version.substr(0, 5) == "HTTP/") { if (status_code == 101 && status_message == "Switching Protocols") { // 连接成功,开始读取websocket数据 ReadWebsocketData(); } else { std::cout << "连接失败: " << status_code << " " << status_message << std::endl; } } else { std::cout << "连接失败: 无效的HTTP响应" << std::endl; } } else { std::cout << "连接失败: " << error.message() << std::endl; } }); } else { std::cout << "连接失败: " << error.message() << std::endl; } }); } else { std::cout << "连接失败: " << error.message() << std::endl; } }); } else { std::cout << "连接失败: " << error.message() << std::endl; } }); } void SendWebsocketData(const std::string& data) { if (m_socket.is_open()) { asio::streambuf streambuf; std::ostream stream(&streambuf); stream << static_cast<char>(0x81); // FIN=1, Opcode=1(Text) stream << static_cast<char>(data.size()); // Payload Length stream.write(data.c_str(), data.size()); // Payload Data asio::async_write(m_socket, streambuf, [this](const asio::error_code& error, std::size_t) { if (error) { std::cout << "发送数据失败: " << error.message() << std::endl; } }); } else { std::cout << "连接已关闭" << std::endl; } } private: void ReadWebsocketData() { asio::async_read(m_socket, asio::buffer(m_buffer), [this](const asio::error_code& error, std::size_t length) { if (!error) { // 解析websocket数据 if (length >= 2) { unsigned char fin = m_buffer[0] & 0x80; unsigned char opcode = m_buffer[0] & 0x0F; unsigned char mask = m_buffer[1] & 0x80; unsigned char payload_length = m_buffer[1] & 0x7F; if (opcode == 1 && mask == 1) { if (payload_length <= 125) { std::string payload_data; for (std::size_t i = 0; i < payload_length; i++) { payload_data += m_buffer[2 + i] ^ m_buffer[(i % 4) + 6]; } std::cout << "接收到数据: " << payload_data << std::endl; } else { std::cout << "接收到数据: 数据长度超过125" << std::endl; } } else { std::cout << "接收到数据: 不是文本消息" << std::endl; } } // 继续读取websocket数据 ReadWebsocketData(); } else { std::cout << "连接已关闭" << std::endl; } }); } private: tcp::resolver m_resolver; tcp::socket m_socket; std::string m_server; std::string m_path; asio::streambuf m_response; std::array<char, 1024> m_buffer; }; int main() { asio::io_context io_context; WebsocketClient client(io_context, "echo.websocket.org", "/v1/"); client.Connect(); while (true) { std::string message; std::cout << "请输入要发送的数据: "; std::getline(std::cin, message); if (!message.empty()) { client.SendWebsocketData(message); } } return 0; } ``` 该程序连接到 `echo.websocket.org` 服务器,并在控制台中等待用户输入websocket数据。它通过发送HTTP请求将连接升级到websocket,并在连接成功后开始读取websocket数据。它还提供了一个 `SendWebsocketData` 方法,以便用户可以在控制台中输入数据并发送到服务器。当程序接收到websocket数据时,它会解析数据并显示在控制台中。 注意:该示例程序仅用于演示如何使用asio实现websocket客户端。实际上,websocket协议比示例程序复杂得多,需要处理更多的细节和错误情况。如果要在生产环境中使用websocket客户端,请使用现有的websocket库,例如 `websocketpp` 或 `boost.beast`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值