所有文章 > API开发 > C#与C++交互开发系列:跨进程通信之使用基于HTTP协议的REST风格的API

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. 1. Boost.Asio:提供跨平台的异步 I/O 功能,适用于构建高效的 TCP、UDP 等网络应用。
  2. 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官网[1]下载并安装。或者通过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) {
// 设置URL
curl_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,这是一个高效的跨平台通信协议,非常适合高性能需求的场景。

文章转自微信公众号@dotnet研习社

#你可能也喜欢这些API文章!