C#与C++交互开发系列(二十二):跨进程通信之使用基于HTTP协议的REST风格的API

在这里插入图片描述

1. 前言

REST API(Representational State Transfer Application Programming Interface)是一种基于HTTP协议的通信方式,广泛用于网络服务和分布式应用程序之间的通信。通过REST API,可以让C#和C++应用程序进行跨进程、甚至跨平台的通信。本文将详细讲解如何使用REST API实现C#和C++程序之间的通信,并附上可真实调试的代码示例。

2. REST API简介

在这里插入图片描述
REST是一种架构风格,利用HTTP协议中的GET、POST、PUT、DELETE等方法与服务器交互,通常用于客户端和服务器之间的数据交换。REST API通信的核心在于定义资源,客户端通过URL访问服务器上的资源,并通过HTTP方法操作这些资源。

3. C++构建服务端和C#构建客户端实现双向交互

1. C++构建Restful服务端

Boost 是一个广受欢迎的 C++ 开源库集合,提供了诸多用于跨平台开发的实用工具。Boost 涵盖了从算法到 I/O、正则表达式、容器和多线程等多种功能,尤其适合构建高性能的服务器、网络和系统应用。我们就使用 Boost库构建一个 RESTful 风格的 C++ Web API。

1.1 Boost库的核心依赖

在这里插入图片描述

我们主要使用两个核心库:

  1. Boost.Asio:提供跨平台的异步 I/O 功能,适用于构建高效的 TCP、UDP 等网络应用。
  2. Boost.Beast:基于 Boost.Asio 实现的 HTTP 和 WebSocket 协议库,简化了 RESTful API 的构建。

通过vcpkg命令安装 Boost.Asio库

vcpkg install boost-asio

在这里插入图片描述
通过vcpkg命令安装 Boost.Beast库

vcpkg install boost-beast

在这里插入图片描述

1.2 构建 RESTful C++ Web API

使用 Boost.Beast 构建一个简单的 RESTful API 服务,支持基本的 CRUD(创建、读取、更新、删除)操作。我们的 API 将运行在端口 8080 上,支持以下路径:

  • GET /api/data:获取数据列表
  • POST /api/data:创建新数据
  • PUT /api/data:更新数据
  • DELETE /api/data:删除数据
1.3 编码实现服务端代码
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <string>
#include <thread>namespace asio = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = asio::ip::tcp;std::string data_store = "Sample data";  // 简单的数据存储// 处理 HTTP 请求的函数
void handle_request(const http::request<http::string_body>& req, http::response<http::string_body>& res) {if (req.method() == http::verb::get && req.target() == "/api/data") {res.result(http::status::ok);res.set(http::field::content_type, "application/json");res.body() = R"({"data": ")" + data_store + R"("})";}else if (req.method() == http::verb::post && req.target() == "/api/data") {data_store = req.body();res.result(http::status::created);res.set(http::field::content_type, "application/json");res.body() = R"({"message": "Data created"})";}else if (req.method() == http::verb::put && req.target() == "/api/data") {data_store = req.body();res.result(http::status::ok);res.set(http::field::content_type, "application/json");res.body() = R"({"message": "Data updated"})";}else if (req.method() == http::verb::delete_ && req.target() == "/api/data") {data_store.clear();res.result(http::status::ok);res.set(http::field::content_type, "application/json");res.body() = R"({"message": "Data deleted"})";}else {res.result(http::status::not_found);res.set(http::field::content_type, "application/json");res.body() = R"({"error": "Resource not found"})";}res.prepare_payload();
}// 会话处理
void session(tcp::socket socket) {beast::flat_buffer buffer;http::request<http::string_body> req;http::response<http::string_body> res;try {http::read(socket, buffer, req);handle_request(req, res);http::write(socket, res);} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}
}// 主程序启动服务器
int main() {try {asio::io_context ioc;tcp::acceptor acceptor(ioc, tcp::endpoint(tcp::v4(), 8080));std::cout << "Server running on http://localhost:8080\n";while (true) {tcp::socket socket(ioc);acceptor.accept(socket);std::thread(&session, std::move(socket)).detach();}} catch (const std::exception& e) {std::cerr << "Server error: " << e.what() << std::endl;}return 0;
}
1.4 启动服务程序

在这里插入图片描述
访问地址:http://localhost:8080/
在这里插入图片描述
访问地址:http://localhost:8080/api/data
在这里插入图片描述

2. 构建C#客户端调用C++ RESTful API

使用 C# 的 HttpClient 调用 C++ RESTful API 并进行数据交互。

2.1 编码实现客户端代码
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;namespace CppWebApiClient
{class Program{private static readonly HttpClient client = new HttpClient();static async Task Main(string[] args){// GET 请求HttpResponseMessage response = await client.GetAsync("http://localhost:8080/api/data");string getData = await response.Content.ReadAsStringAsync();Console.WriteLine("GET Response: " + getData);// POST 请求string newData = "\"New sample data\"";response = await client.PostAsync("http://localhost:8080/api/data", new StringContent(newData, Encoding.UTF8, "application/json"));Console.WriteLine("POST Response: " + await response.Content.ReadAsStringAsync());// PUT 请求string updateData = "\"Updated data\"";response = await client.PutAsync("http://localhost:8080/api/data", new StringContent(updateData, Encoding.UTF8, "application/json"));Console.WriteLine("PUT Response: " + await response.Content.ReadAsStringAsync());// DELETE 请求response = await client.DeleteAsync("http://localhost:8080/api/data");Console.WriteLine("DELETE Response: " + await response.Content.ReadAsStringAsync());Console.ReadKey();}}
}

启动客户端程序
在这里插入图片描述
访问地址:http://localhost:8080/api/data
在这里插入图片描述
数据已被删除。

4. C++构建客户端和C#构建服务端实现双向交互

我们将通过两个部分来构建一个RESTful风格的API服务(使用ASP.NET Core WebAPI)以及如何在C++中调用这个WebAPI。

1. 构建ASP.NET Core WebAPI服务

  1. 创建ASP.NET Core WebAPI项目

    • 打开命令行或Visual Studio。
    • 创建一个新的ASP.NET Core WebAPI项目:
      dotnet new webapi -n MyApi
      cd MyApi
      
  2. 定义一个简单的Controller

    我们创建一个简单的Controller ProductsController.cs,提供几个GET和POST的接口

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using System.Collections.Generic;	
    namespace MyApi.Controllers
    {public class ProductRequest{public string Product { get; set; }}	[Route("api/[controller]")][ApiController]public class ProductsController : ControllerBase{// 这是一个存储产品的示例private static readonly List<string> Products = new List<string>{"Product1","Product2","Product3"};	// 获取所有产品[HttpGet]public ActionResult<IEnumerable<string>> Get(){return Ok(Products);}	// 获取单个产品[HttpGet("{id}")]public ActionResult<string> Get(int id){if (id < 0 || id >= Products.Count){return NotFound();}return Ok(Products[id]);}	// 创建新产品[HttpPost]public ActionResult Post([FromBody] ProductRequest product){if (string.IsNullOrEmpty(product?.Product)){return BadRequest("Product cannot be empty");}Products.Add(product.Product);return CreatedAtAction(nameof(Get), new { id = Products.Count - 1 }, product);}}
    }
    
  3. 运行API
    在命令行中,运行以下命令启动API服务器:

    dotnet run
    

在这里插入图片描述

2. 构建C++客户端调用WebAPI

现在,我们已经创建了一个基本的WebAPI服务。接下来,我们将在C++中编写代码,通过HTTP请求来调用这个WebAPI。为了发送HTTP请求,C++没有内置的库,因此我们将使用一些第三方库,如libcurl

  1. 安装libcurl库

    可以从libcurl官网下载并安装。
    或者通过vcpkg安装
    vcpkg install curl 在这里插入图片描述

  2. C++代码:使用libcurl调用WebAPI

    在C++中,我们将使用libcurl库来发送HTTP请求。

    #include <iostream>
    #include <string>
    #include <curl/curl.h>	
    // 回调函数,用于处理HTTP响应数据
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {size_t totalSize = size * nmemb;((std::string*)userp)->append((char*)contents, totalSize);return totalSize;
    }	
    // GET请求
    void GetProducts() {CURL* curl;CURLcode res;std::string readBuffer;	curl_global_init(CURL_GLOBAL_DEFAULT);curl = curl_easy_init();	if (curl) {curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:5056/api/products");curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);	// 执行请求res = curl_easy_perform(curl);	// 检查请求是否成功if (res != CURLE_OK) {std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;}else {std::cout << "Response: " << readBuffer << std::endl;}	curl_easy_cleanup(curl);}	curl_global_cleanup();
    }// POST请求
    void AddProduct(const std::string& product) {CURL* curl;CURLcode res;std::string readBuffer;	curl_global_init(CURL_GLOBAL_DEFAULT);curl = curl_easy_init();	if (curl) {// 设置URLcurl_easy_setopt(curl, CURLOPT_URL, "http://localhost:5056/api/products");	// 设置HTTP头struct curl_slist* headers = NULL;headers = curl_slist_append(headers, "Content-Type: application/json");	// 设置POST数据std::string jsonData = "{\"product\":\"" + product + "\"}";	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());	// 处理响应curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);	// 执行请求res = curl_easy_perform(curl);// 检查请求是否成功if (res != CURLE_OK) {std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;}else {std::cout << "Response: " << readBuffer << std::endl;}curl_easy_cleanup(curl);curl_slist_free_all(headers);}curl_global_cleanup();
    }	
    int main() {// 获取所有产品GetProducts();// 添加新产品AddProduct("Product4");// 获取所有产品,查看是否添加成功GetProducts();int i;std::cin >> i;return 0;
    }
    
  3. 编译并运行C++代码 在这里插入图片描述

5. 注意事项

  1. 安全性:在生产环境中,请使用SSL证书,确保API通信的安全性。在开发环境中可以临时禁用SSL验证。
  2. 数据格式:通常REST API使用JSON格式传递数据,便于解析。
  3. 错误处理:在生产中,要添加错误处理,捕获网络问题和API错误状态码,确保程序稳定性。

6. 应用场景

  • 跨平台通信:REST API允许不同编程语言和平台的程序通过HTTP协议进行通信,适用于需要跨平台数据交互的项目。
  • 网络服务:REST API广泛用于微服务架构,可实现松耦合的服务部署和集成。

7. 优缺点

  • 优点
    • 标准化的HTTP协议,支持跨平台通信。
    • 支持不同的数据格式,如JSON和XML,数据处理灵活。
  • 缺点
    • 通信效率受限于网络性能,特别是在传输大量数据时可能带来延迟。
    • 使用HTTP请求可能比本地IPC方法(如命名管道、共享内存等)稍慢。

8. 总结

REST API 提供了一种灵活且标准化的通信方式,能够在不同语言和平台间实现通信。通过本文的示例代码,C++ 和 C# 程序可以借助 REST API 实现数据交互。这种方法尤其适合分布式应用和微服务架构的设计。
在下一篇中,我们将介绍gRPC,这是一个高效的跨平台通信协议,非常适合高性能需求的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/14907.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

想让三维模型与实时视频融合?这款软件值得一试

视频融合&#xff0c;是指将视频数据投影到地理特征表面&#xff0c;并通过相应姿态参数控制投影效果的一种三维展示方式&#xff0c;实现了三维模型与实时视频的融合。 四维轻云是一款轻量化的地理空间数据管理云平台&#xff0c;支持地理空间数据的在线管理、编辑以及分享。…

汉化版WinHex和CFF Explorer下载及程序脱壳后修复,重建引入表,修改程序PE文件(附下载链接)

前言 现有一个加壳程序&#xff0c;要求对程序脱壳&#xff0c;需要修复脱壳后的程序 使用PEiD查壳&#xff0c;显示为NsPack 1.4 -> Liuxingping [Overlay] * 先定位程序的OEP&#xff0c;使用od打开程序&#xff0c;看到有压入栈的操作 进行查找&#xff0c;查找命令序列…

STM32F407简单驱动步进电机(标准库)

配置 单片机型号&#xff1a;STM32F104ZGT6 步进电机&#xff1a;YK28HB40-01A 驱动器&#xff1a;YKD2204M-Plus 接线方式&#xff1a; pu&#xff1a;接对应的产生PWM的引脚&#xff0c;这里接PF9&#xff0c;对应TIM14_CH1通道&#xff01; pu-&#xff1a;接单片机的G…

linux-DNS解析

dns解析 dns&#xff1a;域名系统&#xff0c;将域名和ip地址互相映射的一个分布式的数据库&#xff0c;方便用户访问互联网。 ip地址&#xff1a;是所有设备和网站在互联网上的唯一地址&#xff0c;通信一定是ip和ip之间的通信。 dns解析&#xff1a;根据域名在互联网当中找…

光伏电站容量计算方法科普

光伏电站的容量计算是设计和评估光伏系统性能的关键步骤。通过了解光伏电站的容量&#xff0c;我们可以预估其发电量&#xff0c;优化系统设计&#xff0c;并确保系统能满足电力需求。本文将详细介绍几种常见的光伏电站容量计算方法&#xff0c;并特别介绍小程序“光伏一点通”…

采集opc da 转 profinet IO项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 应用条件 2 4 查看OPC DA服务器的相关参数 2 5 配置网关采集opc da数据 4 6 用profinet IO协议转发数据 6 7 在服务器上运行仰科OPC DA采集软件 9 8 案例总结 11 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务…

循环矩阵和BCCB矩阵与向量乘积的快速计算——矩阵向量乘积与频域乘积之间的转换

目录 循环矩阵循环矩阵的定义特征值与特征向量循环矩阵的对角化 循环矩阵与向量的乘积 BCCB矩阵BCCB矩阵的定义BCCB矩阵的对角化BCCB 矩阵与向量的乘积BCCB 矩阵与向量乘积的实现 总结 循环矩阵&#xff08;Circulant Matrix&#xff09;和块循环对称矩阵&#xff08;Block Cir…

(动画版)排序算法 -希尔排序

文章目录 1. 希尔排序&#xff08;Shellsort&#xff09;1.1 简介1.2 希尔排序的步骤1.3 希尔排序的C实现1.4 时间复杂度1.5 空间复杂度1.6 希尔排序动画 1. 希尔排序&#xff08;Shellsort&#xff09; 1.1 简介 希尔排序&#xff08;Shells Sort&#xff09;&#xff0c;又…

蓝桥杯每日真题 - 第7天

题目&#xff1a;&#xff08;爬山&#xff09; 题目描述&#xff08;X届 C&C B组X题&#xff09; 解题思路&#xff1a; 前缀和构造&#xff1a;为了高效地计算子数组的和&#xff0c;我们可以先构造前缀和数组 a&#xff0c;其中 a[i] 表示从第 1 个元素到第 i 个元素的…

socketcan-goloang

模拟接收 模拟发送 package mainimport ("context""fmt""go.einride.tech/can""go.einride.tech/can/pkg/candevice""go.einride.tech/can/pkg/socketcan" )func main() {// linux系统设置// sudo ip link add dev can0 ty…

Java期末复习暨学校第五次上机课作业

Java期末复习暨学校第五次上机课作业&#xff1a;掌握类的定义、掌握类的封装、熟悉类的成员方法的调用。 第一题&#xff1a; 先定义两个整形变量x和y&#xff0c;然后showMessage方法打印防御塔的位置。 然后通过new关键字实例化了一个TowerDefense对象t1,并把x赋值为3&…

【目标检测】【Ultralytics-YOLO系列】Windows11下YOLOV5人脸目标检测

【目标检测】【Ultralytics-YOLO系列】Windows11下YOLOV5人脸目标检测 文章目录 【目标检测】【Ultralytics-YOLO系列】Windows11下YOLOV5人脸目标检测前言YOLOV5模型运行环境搭建YOLOV5模型运行数据集准备YOLOV5运行模型训练模型验证模型推理 总结 前言 Ultralytics YOLO 是一…

【启明智显分享】5G CPE与5G路由器到底有什么区别?

5G路由器和5G CPE在功能和应用场景上存在很明显的差异&#xff0c;小编做了详细比较&#xff0c;希望能帮助到你进一步了解他们的区别及应用。 一、定义与功能 5G路由器 5G路由器是一个将5G网络连接转换为Wi-Fi信号的设备&#xff0c;使多个Wi-Fi设备可以通过5G网络进行连接…

【go从零单排】File Paths文件路径

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 中&#xff0c;处理文件路径通常使用 path/filepath 包。这个包提供了一系…

【数据分享】中国渔业统计年鉴(1979-2024) pdf

数据介绍 一、《中国渔业统计年鉴》以正式出版年份标序。其统计数据起讫日期:渔民家庭收支调查起讫时间为 2022年11月1日至2023年10月31日&#xff0c;其他数据起讫时间为2023年1月1日至2023年12月31日。 二、统计数据中&#xff0c;远洋渔业数据按照远洋渔业管理办法进行统计…

Windows10“大限”将至或加速政企信创进程

近日&#xff0c;微软公司正式宣布将于2025年10月14日终止对Windows 10系统的支持服务。Windows 10“退休”在即&#xff0c;信息安全风险陡增——对此&#xff0c;360织语的安全专家认为&#xff0c;对于政企用户而言&#xff0c;不管是选择继续使用Windows 10&#xff0c;还是…

文本嵌入方案大总结:从词向量到句向量

这里写目录标题 文本嵌入方案总结一、文本嵌入三种层次 词向量应用&#xff1a; 句向量应用&#xff1a; 扩展&#xff1a;文本嵌入和句子相似度、文本匹配的逻辑关系&#xff1f; 二、词向量有哪些方案、优缺点、工具&#xff1f;方案一&#xff1a;统计编码方案二&…

第23天Linux下常用工具(二)

目录 第四章 GDB调试工具 4.1gdb的作用 4.2调试代码的流程 4.3gdb的安装 4.4 gdb的使用 第五章 makefile工程管理工具 5.1makefile的作用 5.2makefile的运行 5.3make的安装 5.4makefile的编写方法 5.5makefile的语法 5.6makefile使用示例 第四章 GDB调试工具 4.1g…

ubuntu22.04与ubuntu24.10使用Remmina远程桌面共享

1. ubuntu22.04启用远程桌面共享 点击Remote Desktop,按下图设置 成功启用 2.ubuntu24.10远程桌面启用 选择远程桌面选项 启用远程桌面共享与远程控制 启用远程登陆

基于51单片机的高压锅控制系统proteus仿真

地址&#xff1a; https://pan.baidu.com/s/16BuxmKYUprTGbkEj_BWGvQ 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…