【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://xiahunao.cn/news/3225970.html

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

相关文章

提升Selenium在Chrome上的HTML5视频捕获效果的五个方法

在使用Selenium进行网页自动化测试时&#xff0c;捕获HTML5视频是一个常见的需求。然而&#xff0c;许多开发者发现&#xff0c;在使用Chrome浏览器时&#xff0c;视频捕获效果并不理想&#xff0c;经常出现视频背景为空白的问题。本文将概述五种方法&#xff0c;帮助提升Selen…

边框插画:成都亚恒丰创教育科技有限公司

边框插画&#xff1a;艺术与生活的精致边界 在视觉艺术的广阔天地里&#xff0c;边框插画以其独特的魅力和细腻的表达方式&#xff0c;成为连接艺术与生活的一道精致边界。成都亚恒丰创教育科技有限公司它不仅仅是图像的外框装饰&#xff0c;更是情感、故事与创意的延伸&#…

从天空到地面:无人机航拍推流直播技术在洞庭湖决口封堵中的全方位支援

据新闻报道&#xff0c;受持续强降雨影响&#xff0c;湖南省华容县团洲垸洞庭湖一线堤防发生管涌险情&#xff0c;随后出现决口。截至7月8日20时左右&#xff0c;226米长的洞庭湖一线堤防决口已累计进占208米&#xff0c;目前剩余18米&#xff0c;有望在今晚或9日凌晨实现合龙。…

Geoserver源码解读六 插件

系列文章目录 Geoserver源码解读一 环境搭建 Geoserver源码解读二 主入口 Geoserver源码解读三 GeoServerBasePage Geoserver源码解读四 REST服务 Geoserver源码解读五 Catalog Geoserver源码解读六 插件&#xff08;怎么在开发模式下使用&#xff09; 目录 系列文章目…

微软Win11 24H2七月更新补丁KB5040435发布!附下载

系统之家于7月10日发出最新报道&#xff0c;微软为Win11用户发布了24H2版本七月的最新更新补丁KB5040435。用户升级系统后&#xff0c;会发现版本号升至 26100.1150。此次更新针对远程身份验证拨入用户服务(RADIUS)协议与 MD5冲突等问题进行修复。接下来跟随小编看看此次更新的…

中国 水文站 分布 矢量数据

中国 水文站 分布 矢量数据 数据介绍 水文站hydrological station是观测及搜集河流、湖泊、水库等水体的水文、气象资料的基层水文机构。中国把水文站按性质分为基本站和专用站。前者的任务是收集实测资料&#xff0c;提供探索基本水文规律的资料&#xff0c;满足水资源评价、…

两年经验前端带你重学前端框架必会的ajax+node.js+webpack+git等技术 Day3

前端框架必会的&#xff08;ajaxnode.jswebpackgit&#xff09;个人学习心得作业及bug记录 Day3 你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​ gitee https://gitee.com/Qiuner &#x1f339; 如果本…

sdwan是硬件还是网络协议?

SD-WAN&#xff08;Software-Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;并不是一个硬件产品或单一的网络协议&#xff0c;而是结合了软件、硬件和网络技术的一种解决方案。SD-WAN的核心在于其软件定义的特性&#xff0c;它通过软件来控制和管理广域网的…

使用机器学习 最近邻算法(Nearest Neighbors)进行点云分析

使用 NearestNeighbors 进行点云分析 在数据分析和机器学习领域&#xff0c;最近邻算法&#xff08;Nearest Neighbors&#xff09;是一种常用的非参数方法。它广泛应用于分类、回归和聚类分析等任务。下面将介绍如何使用 scikit-learn 库中的 NearestNeighbors 类来进行点云数…

干货!| 针对前端加密爆破的方法及实战案例

一 、概述 现在基本上大部分web应用系统都在后台登录界面对密码使用了js加密&#xff0c;有的是将用户名密码同时进行了加密&#xff0c;对于使用了加密的我们可以利用burp插件直接调用加密函数本地加密后再进行爆破&#xff0c;也可以使用一些工具直接模拟浏览器登录界面进行…

基于 Springboot 红酒庄内部信息管理系统 设计实现

目录 &#x1f4da; 前言 &#x1f4d1;摘要 &#x1f4d1;系统流程 &#x1f4da; 系统架构设计 &#x1f4da; 数据库设计 6.1数据三范式&#xff1a; &#x1f4da; 系统功能的具体实现 &#x1f4ac; 系统登录和首页 系统登录 首页 &#x1f4ac; 用户功能模块 添…

基于JavaSpringBoot+Vue+uniapp微信小程序校园宿舍管理系统设计与实现(论文7000字参考+源码+LW+部署讲解)

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

MES系统看板管理模块详细介绍

车间数字化看板作为一种管理工具&#xff0c;广泛应用于制造业&#xff0c;通过在生产现场设置看板&#xff0c;企业能够实现对生产过程的全面、实时的监控和管理。 MES系统提供实时、准确的看板管理&#xff0c;它可以将生产现场的各种数据实时汇总、分析并展示&#xff0c;帮…

AI绘画comfyui工作流,商业海报设计、Logo设计,一个comfyui工作流就能搞定!

前言 创新设计工作流&#xff1a;轻松打造LOGO和海报 本文涉及的工作流和插件&#xff0c;需要的朋友请扫描免费获取哦 —HAPPY NEW YEAR— 大家好&#xff01;今天我要分享的是一个高效且创新的设计工作流&#xff0c;这一工具由国外的网友无私分享&#xff0c;适用于LOGO设…

11计算机视觉—语义分割与转置卷积

目录 1.语义分割应用语义分割和实例分割2.语义分割数据集:Pascal VOC2012 语义分割数据集预处理数据:我们使用图像增广中的随机裁剪,裁剪输入图像和标签的相同区域。3.转置卷积 上采样填充、步幅和多通道填充步幅多通道转置卷积是一种卷积:重新排列输入和核转置卷积是一种卷…

一举跃升!Cancer Discovery修正后IF30.6!

在科学出版界&#xff0c;影响因子&#xff08;IF&#xff09;被广泛认为是衡量期刊学术影响力的重要指标。每年6月&#xff0c;科睿唯安会发布期刊引证报告&#xff08;JCR&#xff09;&#xff0c;但这并不是最终结果。在10月份&#xff0c;JCR会进行统一的更新&#xff0c;包…

LLM大模型应用中的安全对齐的简单理解

LLM大模型应用中的安全对齐的简单理解 随着人工智能技术的不断发展&#xff0c;大规模语言模型&#xff08;如GPT-4&#xff09;的应用越来越广泛。为了保证这些大模型在实际应用中的性能和安全性&#xff0c;安全对齐&#xff08;Safe Alignment&#xff09;成为一个重要的概…

C语言学习笔记[23]:循环语句while①

C语言除了顺序结构和选择结构还有循环结构 whilefordo...while while循环 //while 语法结构 while(表达式)循环语句; 表达式的结果为真&#xff0c;则执行循环语句&#xff0c;否则循环停止 例如&#xff1a;打印1~10 #include <stdio.h>int main() {int i 1;whil…

PostgreSQL16安装Mac(brew)

问题 最近需要从MySQL切换到PostgreSQL。我得在本地准备一个PostgreSQL。 步骤 使用brew安装postgresql16: arch -arm64 brew install postgresql16启动postgresql16: brew services start postgresql16配置postgresql环境变量&#xff0c;打开环境变量文件&#xff1a; …

[leetcode] largest-divisible-subset 最大整除子集

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> largestDivisibleSubset(vector<int>& nums) {int len nums.size();sort(nums.begin(), nums.end());// 第 1 步&#xff1a;动态规划找出最大子集的个数、最大子集中的最大整…