当前位置: 首页 > news >正文

使用C++11的`std::future`和`std::promise`实现异步网络通信

使用C++11的std::futurestd::promise实现异步网络通信

在现代C++编程中,异步编程是一个重要的主题。C++11引入了std::futurestd::promise,为异步编程提供了强大的工具。本文将详细介绍如何使用std::futurestd::promise实现异步网络通信,并提供丰富的示例代码。

什么是std::futurestd::promise

std::futurestd::promise是C++11标准库中的两个类,用于实现异步操作:

  • std::promise:用于设置一个值或异常,该值或异常可以在另一个线程中被获取。
  • std::future:用于获取由std::promise设置的值或异常。

通过std::promisestd::future,我们可以在一个线程中启动一个异步操作,并在另一个线程中等待其完成。

实现异步网络通信的步骤
  1. 创建Socket:使用socket函数创建一个Socket。
  2. 连接服务器:使用connect函数连接到服务器。
  3. 发送和接收消息:使用sendrecv函数进行消息传递。
  4. 使用std::promisestd::future:在异步操作中使用std::promisestd::future来实现异步通信。
示例代码

以下是实现一个简单的异步TCP客户端的完整代码示例:

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <future>const int PORT = 8080;
const int BUFFER_SIZE = 1024;std::string async_send_receive(const std::string& server_ip, const std::string& message) {// 创建Socketint client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket == -1) {throw std::runtime_error("Failed to create socket");}// 服务器地址sockaddr_in server_addr;std::memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr);// 连接服务器if (connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {close(client_socket);throw std::runtime_error("Failed to connect to server");}// 发送消息send(client_socket, message.c_str(), message.size(), 0);// 接收响应char buffer[BUFFER_SIZE];std::memset(buffer, 0, BUFFER_SIZE);int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);if (bytes_received < 0) {close(client_socket);throw std::runtime_error("Failed to receive response");}// 关闭连接close(client_socket);return std::string(buffer, bytes_received);
}int main() {std::string server_ip = "127.0.0.1";std::string message = "Hello, Server!";// 创建promise和futurestd::promise<std::string> promise;std::future<std::string> future = promise.get_future();// 启动异步任务std::thread([&promise, &server_ip, &message]() {try {std::string response = async_send_receive(server_ip, message);promise.set_value(response);} catch (const std::exception& e) {promise.set_exception(std::current_exception());}}).detach();// 等待并获取结果try {std::string response = future.get();std::cout << "Received response: " << response << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}return 0;
}
代码解析
  1. 创建Socket

    int client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket == -1) {throw std::runtime_error("Failed to create socket");
    }
    

    这行代码创建了一个TCP Socket。AF_INET表示使用IPv4地址,SOCK_STREAM表示使用TCP协议。

  2. 连接服务器

    sockaddr_in server_addr;
    std::memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr);if (connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {close(client_socket);throw std::runtime_error("Failed to connect to server");
    }
    

    这段代码将客户端连接到指定的服务器地址和端口。

  3. 发送和接收消息

    send(client_socket, message.c_str(), message.size(), 0);char buffer[BUFFER_SIZE];
    std::memset(buffer, 0, BUFFER_SIZE);
    int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
    if (bytes_received < 0) {close(client_socket);throw std::runtime_error("Failed to receive response");
    }close(client_socket);return std::string(buffer, bytes_received);
    

    这段代码发送消息给服务器,然后等待接收服务器的响应。接收到响应后,关闭连接并返回响应内容。

  4. 使用std::promisestd::future

    std::promise<std::string> promise;
    std::future<std::string> future = promise.get_future();std::thread([&promise, &server_ip, &message]() {try {std::string response = async_send_receive(server_ip, message);promise.set_value(response);} catch (const std::exception& e) {promise.set_exception(std::current_exception());}
    }).detach();try {std::string response = future.get();std::cout << "Received response: " << response << std::endl;
    } catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;
    }
    

    这段代码创建了一个std::promise对象,并通过get_future方法获取对应的std::future对象。然后启动一个新线程,在新线程中执行异步任务,并将结果设置到std::promise中。主线程等待std::future获取结果,并处理异常。

进一步优化

虽然上述代码实现了一个基本的异步TCP客户端,但在实际应用中,我们可能需要进一步优化和扩展功能:

  1. 错误处理:添加更多的错误处理逻辑,处理各种可能的网络错误。
  2. 超时机制:实现超时机制,避免异步操作无限期等待。
  3. 多线程处理:使用线程池或异步I/O来提高并发性能。
  4. 数据序列化:使用数据序列化技术(如JSON或Protobuf)来传输复杂的数据结构。
超时机制示例

以下是一个实现超时机制的示例:

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <future>
#include <chrono>const int PORT = 8080;
const int BUFFER_SIZE = 1024;std::string async_send_receive(const std::string& server_ip, const std::string& message) {// 创建Socketint client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket == -1) {throw std::runtime_error("Failed to create socket");}// 服务器地址sockaddr_in server_addr;std::memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr);// 连接服务器if (connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {close(client_socket);throw std::runtime_error("Failed to connect to server");}// 发送消息send(client_socket, message.c_str(), message.size(), 0);// 接收响应char buffer[BUFFER_SIZE];std::memset(buffer, 0, BUFFER_SIZE);int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);if (bytes_received < 0) {close(client_socket);throw std::runtime_error("Failed to receive response");}// 关闭连接close(client_socket);return std::string(buffer, bytes_received);
}int main() {std::string server_ip = "127.好的,我们继续。#### 超时机制示例(续)以下是一个实现超时机制的完整示例:```cpp
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <future>
#include <chrono>const int PORT = 8080;
const int BUFFER_SIZE = 1024;std::string async_send_receive(const std::string& server_ip, const std::string& message) {// 创建Socketint client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket == -1) {throw std::runtime_error("Failed to create socket");}// 服务器地址sockaddr_in server_addr;std::memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr);// 连接服务器if (connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {close(client_socket);throw std::runtime_error("Failed to connect to server");}// 发送消息send(client_socket, message.c_str(), message.size(), 0);// 接收响应char buffer[BUFFER_SIZE];std::memset(buffer, 0, BUFFER_SIZE);int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);if (bytes_received < 0) {close(client_socket);throw std::runtime_error("Failed to receive response");}// 关闭连接close(client_socket);return std::string(buffer, bytes_received);
}int main() {std::string server_ip = "127.0.0.1";std::string message = "Hello, Server!";// 创建promise和futurestd::promise<std::string> promise;std::future<std::string> future = promise.get_future();// 启动异步任务std::thread([&promise, &server_ip, &message]() {try {std::string response = async_send_receive(server_ip, message);promise.set_value(response);} catch (const std::exception& e) {promise.set_exception(std::current_exception());}}).detach();// 等待并获取结果,设置超时时间为5秒if (future.wait_for(std::chrono::seconds(5)) == std::future_status::ready) {try {std::string response = future.get();std::cout << "Received response: " << response << std::endl;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}} else {std::cerr << "Request timed out" << std::endl;}return 0;
}

在这个示例中,我们使用std::future::wait_for方法设置了一个超时时间为5秒。如果在5秒内没有收到响应,程序将输出“Request timed out”。

总结

通过本文,我们详细介绍了如何使用C++11的std::futurestd::promise实现异步网络通信。我们探讨了std::futurestd::promise的基本概念、实现异步TCP客户端的具体步骤和代码,并展示了如何实现超时机制。

理解和掌握这些技术可以帮助你在异步编程和网络编程领域取得更大的进步。希望这篇文章能帮助你更好地理解和应用std::futurestd::promise。如果你有任何问题或需要进一步的帮助,请随时联系我。Happy coding!

相关文章:

使用C++11的`std::future`和`std::promise`实现异步网络通信

使用C11的std::future和std::promise实现异步网络通信 在现代C编程中&#xff0c;异步编程是一个重要的主题。C11引入了std::future和std::promise&#xff0c;为异步编程提供了强大的工具。本文将详细介绍如何使用std::future和std::promise实现异步网络通信&#xff0c;并提…...

【C++登堂入室】类与对象(上)

目录 一、面向过程和面向对象初步认识 二、类的引入 三、类的定义 四、类的访问限定符及封装 4.1 访问限定符 4.2 封装 五、类的作用域 六、类的实例化 七、类对象模型 7.1如何计算类对象的大小 7.2 类对象的存储方式猜测 7.3 结构体内存对齐规则 八、this指针 …...

【西电电装实习】5. 无人机模块及作用、上位机的操作

文章目录 前言一、硬件结构电源、电源电压测试电路晶振外围陀螺仪信号放大电路及天线空心杯&#xff08;电极&#xff09;驱动电路 软件设置整机装配PID 参数设置公式 参考文献 前言 西电电装实习&#xff0c;无人机原理图、上位机的调节方法 一、硬件结构 电源、电源电压测试…...

有关WSL和docker的介绍

目录标题 如何利用在windows上配置docker实现linux和windows容器修改WSL默认安装&#xff08;也就是linux子系统&#xff09;目录到其他盘 如何利用在windows上配置docker实现linux和windows容器 wsl的基本命令&#xff1a;参考网页 docker入门到实践&#xff1a;参考网页 官方…...

以太坊入门

1. 以太坊简介 Vitalik Buterin 在 2013 年 11 月提出了以太坊的概念&#xff0c;其关键思想是&#xff1a;开发一种图灵完备&#xff08;Turing-Complete) 的语言&#xff0c;以允许开发用于区块链和去中心化应用的任意程序&#xff08;智能合约&#xff09;。该概念与比特比相…...

秃姐学AI系列之:实战Kaggle比赛:狗的品种识别(ImageNet Dogs)

目录 前置准备 整理数据集 图片增广 读取数据集 微调预训练模型 训练函数 训练和验证模型 Kaggle提交结果 前置准备 常规导包 import os import torch import torchvision from torch import nn from d2l import torch as d2l 使用小规模数据样本 d2l.DATA_HUB[dog…...

图神经网络介绍3

1. 图同构网络&#xff1a;Weisfeiler-Lehman 测试与图神经网络的表达力 本节介绍一个关于图神经网络表达力的经典工作&#xff0c;以及随之产生的另一个重要的模型——图同构网络。图同构问题指的是验证两个图在拓扑结构上是否相同。Weisfeiler-Lehman 测试是一种有效的检验两…...

浅谈 React Fiber

想象一下&#xff0c;你正在搭建一个乐高积木城堡。 传统的搭建方式&#xff1a;一次性把所有积木拼好&#xff0c;如果中途发现某个地方拼错了&#xff0c;就需要拆掉重新拼。这个过程就像 React 15 之前的版本&#xff0c;一旦开始渲染&#xff0c;就很难中断&#xff0c;效…...

Winform实现石头剪刀布小游戏

1、电脑玩家类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace RockScissorsClothApp {public class Computer{public Card Play(){Random random new Random();int num random.Next(0, 3…...

计算机的错误计算(九十)

摘要 计算机的错误计算&#xff08;八十九&#xff09;探讨了反双曲余切函数 acoth(x)在 附近的计算精度问题。本节讨论绝对值为大数的反双曲余切函数值的计算精度问题。 Acoth(x) 函数的定义为&#xff1a; 其中 x 的绝对值大于 1 . 例1. 计算 acoth(1.000000000002e15) .…...

对游戏语音软件Oopz遭遇DDoS攻击后的一些建议

由于武汉天气太热&#xff0c;因此周末两天就没怎么出门。一直在家打《黑神话&#xff1a;悟空》&#xff0c;结果卡在广智这里一直打不过去&#xff0c;本来想找好友一起讨论下该怎么过&#xff0c;但又没有好的游戏语音软件。于是在网上搜索了一些信息&#xff0c;并偶然间发…...

解锁Android开发利器:MVVM架构_android的mvvm

// 从网络或其他数据源获取天气数据return Weather(city, "25C") }} 2.定义View&#xff1a;class WeatherActivity : AppCompatActivity() { private lateinit var viewModel: WeatherViewModel override fun onCreate(savedInstanceState: Bundle?) {super.onCre…...

llama.cpp demo

git clone https://github.com/ggerganov/llama.cpp cd llama.cpp 修改Makefile使能mfma参数 MK_CFLAGS -mfma -mf16c -mavx MK_CXXFLAGS -mfma -mf16c -mavx 安装python3依赖 cat ./requirements/requirements-convert_legacy_llama.txt numpy~1.26.4 sentencepie…...

OpenCV结构分析与形状描述符(19)查找二维点集的最小面积外接旋转矩形函数minAreaRect()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 找到一个包围输入的二维点集的最小面积旋转矩形。 该函数计算并返回指定点集的最小面积边界矩形&#xff08;可能是旋转的&#xff09;。开发者…...

[SWPU2019]Web1 超详细教程

老规矩先看源码&#xff0c;没找到啥提示&#xff0c;后面就是登录口对抗 弱口令试了几个不行&#xff0c;就注册了个账户登录进去 可以发布广告&#xff0c;能造成xss&#xff0c;但是没啥用啊感觉 查看广告信息的时候&#xff0c;注意到url当中存在id参数&#xff0c;可能存…...

【区块链通用服务平台及组件】基于向量数据库与 LLM 的智能合约 Copilot

智能合约是自动执行、无需信任的代码&#xff0c;可以在区块链上运行&#xff0c;确保了数据和程序的透明性和不可篡改性。然而&#xff0c; 智能合约的编写、调试和优化仍然是一个具有挑战性的过程&#xff0c;因为它需要高度的技术专长&#xff0c;且发布后的智能合约代码通常…...

mfc140u.dll丢失有啥方法能够进行修复?分享几种mfc140u.dll丢失的解决办法

你是否曾遇到过这样的情况&#xff1a;当你满怀期待地打开一个应用程序时&#xff0c;却被一个错误提示拦住了去路&#xff0c;提示信息中指出 mfc140u.dll 文件丢失。这个问题可能会让你感到困惑和无助&#xff0c;但是不要担心&#xff0c;本文将为你详细解读 mfc140u.dll 丢…...

【PyQt6 应用程序】在用户登录界面实现密码密文保存复用

在开发现代应用程序中,为用户提供既安全又便捷的登录体验是至关重要的。特别是在那些需要用户认证的应用中,实现一个功能丰富且用户友好的登录界面不仅能增强用户满意度,还能提升整体的安全性。基于PyQt6框架和QtDesigner,本文将展示如何在已有的用户登录页面基础上,进一步…...

赋能百业:多模态处理技术与大模型架构下的AI解决方案落地实践

赋能百业:多模态处理技术与大模型架构下的AI解决方案落地实践 AI 语音交互大模型其实有两种主流的做法: All in LLM多个模块组合, ASR+LLM+TTS实际应用中,这两种方案并不是要对立存在的,像永劫无间这种游戏的场景,用户要的是低延迟,无障碍交流。并且能够触发某些动作技…...

游戏论坛网站|基于Springboot+vue的游戏论坛网站系统游戏分享网站(源码+数据库+文档)

游戏论坛|游戏论坛系统|游戏分享网站 目录 基于Springbootvue的游戏论坛网站系统游戏分享网站 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...

背包问题双雄:01 背包与完全背包详解(Java 实现)

一、背包问题概述 背包问题是动态规划领域的经典问题&#xff0c;其核心在于如何在有限容量的背包中选择物品&#xff0c;使得总价值最大化。根据物品选择规则的不同&#xff0c;主要分为两类&#xff1a; 01 背包&#xff1a;每件物品最多选 1 次&#xff08;选或不选&#…...

k8s从入门到放弃之Pod的容器探针检测

k8s从入门到放弃之Pod的容器探针检测 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;容器探测是指kubelet对容器执行定期诊断的过程&#xff0c;以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...