【C++】使用C++实现基于Socket的通信

在这里插入图片描述

在本文中,我们将详细讨论如何使用C++实现基于Socket的通信,并设计一个TLV(Type-Length-Value)协议用于数据交互。TLV协议因其灵活性和可扩展性,在多种通信协议中被广泛使用,特别是在需要动态定义数据结构的场景中。我们将分步骤实现Socket通信,设计TLV协议,并通过示例代码展示其应用。
在这里插入图片描述

一、Socket通信基础

1.1 Socket简介

Socket是一种网络通信接口,它提供了端到端的通信服务。Socket分为TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)两种类型。TCP是面向连接的、可靠的、基于字节流的传输层通信协议,而UDP则是无连接的、不可靠的、基于数据报的传输层通信协议。

1.2 TCP Socket编程基本步骤

创建Socket:使用socket()函数创建一个新的socket描述符。
绑定Socket:使用bind()函数将socket与特定的IP地址和端口号绑定。
监听连接(服务器端):使用listen()函数使socket进入监听状态,准备接收客户端的连接请求。
接受连接(服务器端):使用accept()函数接受客户端的连接请求,建立连接。
连接服务器(客户端):使用connect()函数与服务器建立连接。
数据读写:使用send()、recv()等函数进行数据的发送和接收。
关闭连接:使用close()函数关闭socket连接。

二、TLV协议设计

TLV(Type-Length-Value)协议是一种简单但强大的数据编码方式,它通过三个主要部分来组织数据:

Type(类型):用于标识Value的类型或用途,通常是一个整数。
Length(长度):表示Value部分的长度,也是一个整数。
Value(值):实际的数据内容,其类型和长度由Type和Length决定。

2.1 TLV数据结构定义

#include <cstdint>  
#include <vector>  
#include <memory>  struct TLVElement {  std::uint16_t type;    // Type部分,通常使用16位整型  std::uint16_t length;  // Length部分,也是16位整型  std::vector<std::uint8_t> value;  // Value部分,使用字节向量存储  // 构造函数、序列化、反序列化等成员函数可以在这里添加  
};  // TLV消息可以看作是一个TLVElement的数组  
using TLVMessage = std::vector<TLVElement>;

2.2 TLV协议的序列化与反序列化

序列化是将TLV消息转换为字节流以便在网络中传输的过程,反序列化则是将接收到的字节流转换回TLV消息的过程。

// 序列化函数示例  
std::vector<std::uint8_t> SerializeTLVMessage(const TLVMessage& message) {  std::vector<std::uint8_t> result;  for (const auto& elem : message) {  // 写入Type  result.push_back(elem.type & 0xFF);  result.push_back((elem.type >> 8) & 0xFF);  // 写入Length  result.push_back(elem.length & 0xFF);  result.push_back((elem.length >> 8) & 0xFF);  // 写入Value  result.insert(result.end(), elem.value.begin(), elem.value.end());  }  return result;  
}  // 反序列化函数需要根据实际情况设计,这里不详细展开

三、C++ Socket编程实现

3.1 服务器端代码实现

#include <iostream>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <unistd.h>  
#include <cstring>  // 假设Socket和TLV的序列化/反序列化已经实现  int main() {  int server_fd, new_socket;  struct sockaddr_in address;  int opt = 1;  int addrlen = sizeof(address);  // 创建socket文件描述符  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {  perror("socket failed");  exit(EXIT_FAILURE);  }  // 强制绑定socket到端口8080  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSE
ADDRPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {  perror("bind failed");  exit(EXIT_FAILURE);  
}  
if (listen(server_fd, 3) < 0) {  perror("listen");  exit(EXIT_FAILURE);  
}  if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {  perror("accept");  exit(EXIT_FAILURE);  
}  // 假设我们有一个TLVMessage需要发送给客户端  
TLVMessage messageToSend;  
// 填充messageToSend...  // 序列化TLVMessage为字节流  
auto serializedData = SerializeTLVMessage(messageToSend);  // 发送数据  
send(new_socket, serializedData.data(), serializedData.size(), 0);  // 关闭socket  
close(new_socket);  
close(server_fd);  return 0;
}

3.2 客户端代码实现

#include <iostream>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#include <cstring>  // 假设Socket和TLV的反序列化函数已经实现  int main() {  struct sockaddr_in serv_addr;  int sock = 0;  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  std::cerr << "Socket creation error" << std::endl;  return -1;  }  serv_addr.sin_family = AF_INET;  serv_addr.sin_port = htons(8080);  // 将IPv4地址从文本转换为二进制形式  if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {  std::cerr << "Invalid address/ Address not supported" << std::endl;  return -1;  }  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {  std::cerr << "Connection Failed" << std::endl;  return -1;  }  // 接收数据  char buffer[1024] = {0};  int valread = read(sock, buffer, 1024);  std::vector<std::uint8_t> receivedData(buffer, buffer + valread);  // 反序列化数据为TLVMessage  TLVMessage receivedMessage = DeserializeTLVMessage(receivedData);  // 处理receivedMessage...  // 关闭socket  close(sock);  return 0;  
}

四、TLV协议在实际应用中的优势与注意事项

4.1 优势

灵活性:TLV协议允许在单个消息中灵活地包含多种类型的数据,每个TLV元素都是独立的,易于扩展和维护。
可扩展性:通过增加新的Type值,可以很容易地添加新的数据类型或功能,而无需修改现有数据的结构。
清晰性:每个TLV元素都明确指出了其类型和长度,这使得数据的解析变得简单明了。

4.2 注意事项

性能:由于每个TLV元素都包含Type和Length字段,这可能会增加消息的开销,特别是在包含大量小元素时。
对齐与填充:在序列化到某些类型的网络或存储设备时,可能需要考虑字节对齐和填充问题,以确保数据的正确性和效率。
错误处理:在反序列化过程中,必须严格检查Type和Length的有效性,以避免数据损坏或安全问题。

五、总结

本文详细讨论了如何使用C++实现基于Socket的通信,并设计了一个TLV协议用于数据交互。我们介绍了Socket编程的基本步骤,包括创建Socket、绑定、监听、接受连接、数据读写和关闭连接等。同时,我们定义了TLV协议的数据结构,并展示了如何将其序列化为字节流以便在网络中

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Axure】产品原型如何在谷歌浏览器中打开

作为一名前端开发来说&#xff0c;在拿到产品的原型图后&#xff0c;如何打开&#xff1f;直接用谷歌浏览器打开&#xff0c;是打不开的&#xff0c;需要安装对应的插件。但是谷歌插件市场在不翻墙的情况下&#xff0c;是没有办法直接打开的&#xff0c;分享一种超级简单的方法…

深入解析RocketMQ的名字服务机制:功能、原理与应用

NameServer 是专为 RocketMQ 设计的轻量级名字服务&#xff0c;它的源码非常精简&#xff0c;八个类 &#xff0c;少于 1000 行代码。 这篇文章&#xff0c; 笔者会从基础概念、Broker 发送心跳包、NameServer 维护路由、Zookeeper vs NameServer 四个模块揭秘名字服务的设计精…

电脑怎样连接打印机?详细步骤告诉你!

在现代办公环境中&#xff0c;打印机是必不可少的设备之一。无论是打印文档、图片还是其他资料&#xff0c;连接打印机都是我们日常工作中的基本操作。然而&#xff0c;不同类型的打印机和连接方式可能会让人感到困惑。本文将介绍电脑怎样连接打印机的3种方法&#xff0c;帮助您…

hnust 1497: 中国象棋中的跳马问题

hnust 1497: 中国象棋中的跳马问题 题目描述 现在棋盘的大小不一定&#xff0c;由p&#xff0c;q给出&#xff0c;并且在棋盘中将出现障碍物&#xff08;限制马的行动&#xff0c;与象棋走法相同&#xff09; 输入 第一行输入n表示有n组测试数据。 每组测试数据第一行输入2个整…

《警世贤文》摘抄:勤奋篇、取财篇、疏财篇、是非篇、安心篇、防忧篇(多读书、多看报、少吃零食多睡觉)

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140319751 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

简易限流实现

需求描述 写一个1秒两个的限流工具类&#xff0c;2r/s 使用semaphore 代码实现-类似令牌桶算法 public class LimitHelper {private int maxLimit;private Semaphore semaphore;private int timeoutSeconds;public LimitHelper(int maxLimit, int timeoutSeconds) {this.max…

LNMP搭建Discuz和Wordpress

1、LNMP L:linux操作系统 N&#xff1a;nginx展示前端页面web服务 M&#xff1a;mysql数据库&#xff0c;保存用户和密码&#xff0c;以及论坛相关的内容 P&#xff1a;php动态请求转发的中间件 数据库的作用&#xff1a; 登录时验证用户名和密码 创建用户和密码 发布和…

昇思25天学习打卡营第十七天|文本解码原理--以MindNLP为例

背景 提供免费算力支持&#xff0c;有交流群有值班教师答疑的华为昇思训练营进入第十七天了。 今天是第十七天&#xff0c;从第十天开始&#xff0c;进入了应用实战阶段&#xff0c;前九天都是基础入门阶段&#xff0c;具体的学习内容可以看链接 基础学习部分 昇思25天学习打卡…

Unity发布webgl之后修改StreamingAssets 内的配置文件读取到的还是之前的配置文件的解决方案

问题描述 unity发布webgl之后&#xff0c;修改在StreamingAssets 中的配置信息&#xff0c;修改之后读取的还是之前的配置信息 读取配置文件的代码IEnumerator IE_WebGL_LoadWebSocketServerCopnfig(){var uri new System.Uri(Path.Combine(Application.streamingAssetsPath…

居家客服人员分散,更需要统一客服话术

1、居家客服服务需求激增 近年来&#xff0c;随着线上消费的兴起&#xff0c;以及客服人员成本的不断攀升&#xff0c;越来越多的企业选择雇佣居家客服&#xff0c;以客服服务发包的形式接待客户的咨询。因此&#xff0c;居家客服人员的数量也逐渐增加。然而&#xff0c;居家办…

c++ 多边形 xyz 数据 获取 中心点方法

有需求需要对。多边形 获取中心点方法&#xff0c;绝大多数都是 puthon和java版本。立体几何学中的知识。 封装函数 point ##########::getCenterOfGravity(std::vector<point> polygon) {if (polygon.size() < 2)return point();auto Area [](point p0, point p1, p…

nftables(4)表达式(2)主要表达式(PRIMARY EXPRESSIONS)

简介 上篇文章已经介绍了数据类型&#xff0c;如INTERGER TYPE、BITMASK TYPE、STRING TYPE、LINK LAYER ADDRESS TYPE、 IPV4 ADDRESS TYPE、 IPV6 ADDRESS TYPE、BOOLEAN TYPE、ICMP TYPE、CONNTRACK TYPES等。那么本篇文章主要介绍PRIMARY表达式的相关内容。 PRIMARY EXPR…

PHP充电桩小程序系统源码

绿色出行新伴侣&#xff01;充电桩小程序&#xff0c;让充电不再烦恼✨ &#x1f50b; 开篇&#xff1a;告别电量焦虑&#xff0c;充电桩小程序来救场&#xff01; 在这个电动车日益普及的时代&#xff0c;电量不足成了不少车主的“心头大患”。但别担心&#xff0c;充电桩小…

记一次mysql导出到达梦数据库

DM8管理工具 DM管理工具&#xff08;官方&#xff09;DBeaver - jdbc驱动 MySql迁移到DM8 使用官方DM数据迁移工具 新建迁移工程选择MySQL>DM填写mysql连接信息、添加dm连接信息执行 DM8数据脚本制作过程 使用DM管理工具 导出全部&#xff1a;进入对应模式>表>选…

nprogress进度条插件

打开一个页面时&#xff0c;往往会伴随一些请求&#xff0c;并且会在页面上方出现进度条。它的原理时&#xff0c;在我们发起请求的时候开启进度条&#xff0c;在请求成功后关闭进度条&#xff0c;所以只需要在request.js中进行配置。 如下图所示&#xff0c;我们页面加载时发起…

grblHAL的代码学习笔记和解读

源代码在 https://github.com/grblHal 目前日期2024/07/09 或许几年以后代码会做变更. 仅供参考. grbl是个很好的库. grblHAL是在grbl的基础上改进来的. grbl的板子通过串口或者SD卡或网络与上位机进行通信, 上位机负责查看和人机交互. 上位机把CAM软件生成的代码读入以后,转换…

docker pull rabbimq镜像失败

在使用docker pull rabbitmq的镜像的时候&#xff0c;找了好多源&#xff0c;都报错如下&#xff1a; Error response from daemon: toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.dock…

3.上传图片(阿里云空间,oss验证)

笔记 20240710 未验证&#xff0c;现在还没有阿里云空间&#xff0c;等买个sit环境就可以验证一下。 前端 页面 <!--页面--> <el-form-item label"优惠券图片" prop"couponImg"><single-upload v-model"dataForm.couponImg"&g…

【R语言+Gephi】利用R语言和Gephi实现共发生网络的可视化

【R语言Gephi】利用R语言和Gephi实现共发生网络的可视化 注&#xff1a;本文仅作为自己的学习记录以备以后复习查阅 一 概述 Gephi是一款开源免费的多平台网络分析软件&#xff0c;在Windows、Linux和Mac os上均可以运行&#xff0c;像他们官网所说的&#xff0c;他们致力于…

【深度学习】Pytorch完成线性回归!

&#x1f34a;嗨&#xff0c;大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; )&#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官、CSDN人工智能领域优质创作者 。 易编橙&#xff1a;一个帮助编程小…