网络编程/在哪些场景中不必要进行网络字节序转换? Windows Sockets: Byte Ordering

news2024/12/24 11:41:06

文章目录

  • 概述
  • 字节序
  • 必须转换字节序的的情况
  • 不必转换字节序的的情况
  • 字节序转换的例程
  • 字节序转换函数
  • 字节序转换可以不生硬
  • 字节序和位序

概述

本文主要讲述了在哪些场景下必须要进行大小端字节序转换,在哪些场景下可以不用进行大小端字节序转换,IP和端口号转网络字节序的必要性、避免应用数据逐个字段生硬转字节序的方法。在 MSDN Windows Sockets: Byte Ordering 帮助文档案例的基础上,略微延伸,以对网络字节序应用场景、主机字节序与网络字节序结构定义和转换方法,形成更直观些的认识。

@History
对于大部分猿,很少会碰到真正需要字节序转换的场景,相关官方资料也并不多。偶然在MSDN中发现了, Windows Sockets: Byte Ordering 这篇文章,其讲述的是 Windows 套接字编程系列问题。你可以在MSDN查看器中搜索,也可以按照上述连接来跳转在线帮助页面,本文基于上述文章内容,进行了适当的展开说明,其大场景是基于 Windows Sockets 的,还掺杂了MFC的宣教,多少带着些片面,但这并不妨碍其给我们带来期望的启迪。

转载请标明出处,
https://blog.csdn.net/quguanxin/category_10527523.html

字节序

在《存储与传输/大小端字节序的概念、决定因素、给编程带来的困扰》文章中,已经详细的描述了大小端字节序的名称的来源及其概念的记忆方法,这里不再赘述。该小节是 MSDN 中对 Intel 处理器字节序的一个简短说明。

不同的机器架构有时会使用不同的字节顺序存储数据。例如,基于 Intel 的机器使用的字节顺序与 Macintosh (Motorola) 机器相反。Intel 的字节顺序被称为"小端"(Little-Endian),也与网络标准的"大端"(Big-Endian)顺序相反。大端字节序和小端字节序的具体表述如下:
在这里插入图片描述
通常情况下,在通过网络发送和接收数据时,你不需要担心字节顺序的转换。但是,也存在一些情况下你必须进行字节顺序的转换。

在这里插入图片描述

必须转换字节序的的情况

你需要在以下情况下进行字节顺序转换:
在这里插入图片描述
1、当你需要传递一些信息,而这些信息需要被 [network] ( 网络(设备))正确解释,而不是仅仅(as opposed to )传递数据(与前半句的待传递信息对应)给另一台机器。例如,你可能需要传递端口号和地址,这些信息必须被网络设备正确理解。而此处所谓的network网络设备可能是指,路由器、交换机、防火墙、负载均衡器等,如果不进行适当的字节顺序转换,这些网络设备可能无法正确地解析和处理端口号和IP地址等信息,更直接的描述是,人家这些通用网络设备都遵循了网络字节序规则,因此你也要遵循。
我们也该注意到另一个问题,就是上述网络设备,它只能解析到端口和地址等TCP/IP头的字段,而对于应用层数据段,它们不关心也没有依据去解析数据内容。只有参与通信的终端设备才会知道数据内容的真正含义,也才有可能进行多字节数据的字节序转换。
由上述分析可以衍生出来1个小结论,网路字节序在TCP/IP层,也即在网络设备上被解析的层次上,其强制性要更高,是必须要遵守的。对应的,在应用层数据段上,这种强制性显得略弱一些,不是必须遵守的。

2、如果你正在与一个服务器应用程序通信,而该服务程序不是 MFC 应用程序(并且你没有它的源代码)。这是因为(this calls for),两台机器可能使用不同的字节序,需要进行转换以确保数据能够正确传输和解释。

也要注意的是,并不是只有涉及到网络通信时才会产生大小端的需求。一些其他的情况,如,
1、存储和传输数据: 如果你需要在不同的平台之间传输数据,并且这些平台使用不同的字节顺序,则需要进行字节顺序转换。否则,数据可能会被错误地解释。
2、跨平台编程: 当在不同架构的机器上运行程序时,如果程序需要在本地使用数据,则必须确保数据的字节顺序正确。这通常需要在读取和写入数据时进行转换。

不必转换字节序的的情况

在如下情况下,没有必要进行字节序转换。
在这里插入图片描述
1、通信双方使用相同的字节序,且已经约定好了都不进行字节序变换。
2、你正在与之通信的服务是基于MFC应用程序。不要过度解读这句话,说这句话的前提是,上下文中谈论的是windows套接字,而不是其他平台或系统,MFC 的特殊性在于它与 Windows 操作系统深度集成,可以确保字节序的一致性,从而免去了手动转换的需要。
3、你正在与之通信的服务程序,你持有它的源代码,基于此,你可以清楚明确地(explicitly)辨别出是否需要进行字节序转换。
4、您可以将服务器程序port移植到 MFC 平台上。这通常比较容易实现,而且最终得到的代码通常会更小、运行更快。感觉是套话。

接下来的这两段,与MFC太过密切,

先简单扩展下,CAsyncSocket 是 MFC 提供的一个基础的异步 Socket 类。它提供了Socket编程的基本功能,如创建、连接、收发数据等,使用 CAsyncSocket 需要自己处理字节序转换等细节。CArchive 是 MFC 的一个序列化类,用于对数据进行序列化和反序列化。它会自动处理字节序转换的细节,确保数据在不同字节序的平台间传输正确。CSocket 是建立在 CAsyncSocket 之上的一个更高级的 Socket 类。它集成了数据流读写操作,使用更加方便,其内部会使用 CArchive 类来处理字节序转换。

在使用 CAsyncSocket 时,您必须自行管理任何必要的字节顺序转换。Windows Sockets 采用了"大端"字节顺序模型作为标准,并提供了函数来在这种顺序与其他顺序之间进行转换。但是,您在使用 CSocket 时会用到 CArchive,它使用的是相反的(“小端”)顺序。不过 CArchive 会自动处理好字节顺序转换的细节。通过在您的应用程序中使用这种标准的字节顺序,或者使用 Windows Sockets 提供的字节顺序转换函数,您可以使您的代码更加可移植。

使用 MFC Sockets 的理想情况是当您正在编写通信的双方都使用 MFC 时。但是,如果您正在编写一个应用程序,它需要与非 MFC 应用程序(如 FTP 服务器)进行通信,那么在将数据传递给 Archive 对象之前,您很可能需要自己管理字节交换,使用 Windows Sockets 提供的 ntohs、ntohl、htons 和 htonl 等转换函数。本文稍后会给出一个与非 MFC 应用程序进行通信时使用这些函数的示例。当通信的另一端不是 MFC 应用程序时,您还必须避免将从 CObject 派生的 C++ 对象流式传输到您的 Archive 中,因为接收端无法处理这些对象。

字节序转换的例程

很长的一段时间内,我苦于找不到有字节序转换的实际场景,我怀着一颗无比好奇的心开始了本例程的阅读。接下来的例程,向我们展示了一个使用Archive的CSocket对象的 serialization function 序列化函数。它还向我们阐明了(illustrates )如何在Windows Socket API 中使用字节序转换函数。示例中提出presents了一个如下场景scenario,
你要写一个客户端与服务端通信,但是该服务端不是基于MFC平台的,且你不能访问到该服务端程序的源代码。在此情景下,你必须假定这个服务端程序使用的是标准网络字节序。in contrast 相比之下,您的 MFC 客户端应用程序使用了一个 CSocket 对象和一个 CArchive 对象,而 CArchive 使用 “小端” 字节顺序,这与网络标准的 “大端” 字节顺序相反。

假设你计划与之通信的服务程序,已经制定 established 了的如下所示的消息包协议,protocol for a message packet
在这里插入图片描述

你要写的基于MFC的客户端,对应的消息结构如下,

struct Message {
    long m_lMagicNumber;
    short m_nCommand;
    short m_nParam1;
    long m_lParam2;
    void Serialize( CArchive& ar );
};

在C++中,一个结构体本质上与一个类是一致的,上述Message结构可以具有一个成员函数,如上述Serialize成员函数,该函数实现大约如下,

void Message::Serialize(CArchive& ar)  {
    if (ar.IsStoring()) {
        ar << (DWORD)htonl(m_lMagicNumber);   //将网络字节序转换为主机字节序小端后,再序列化
        ar << (WORD)htons(m_nCommand);
        ar << (WORD)htons(m_nParam1);
        ar << (DWORD)htonl(m_lParam2);
    }
    else    {
        WORD w;
        DWORD dw;
        ar >> dw;
        m_lMagicNumber = ntohl((long)dw);    //在反序列化的过程中,将小端存储的数据转成大端字节序
        ar >> w ;
        m_nCommand = ntohs((short)w);
        ar >> w;
        m_nParam1 = ntohs((short)w);
        ar >> dw;
        m_lParam2 = ntohl((long)dw);
    }
}

如上,该示例需要进行字节顺序转换,因为非 MFC 的服务器应用程序,其字节顺序与 MFC 客户端应用程序使用的 CArchive 的字节顺序存在明显的不匹配。

字节序转换函数

上述示例演示了 Windows Sockets 提供的几个字节顺序转换函数。下表描述了这些函数:
在这里插入图片描述
英语单词 quantity 不仅具有数量、大量等意思,还有数值的意思,如上 32-bit quantity 表示一个32比特的数值。 以htonl函数为例,

//host to net long int 
u_long htonl([in] u_long hostlong);

在这里插入图片描述
如上,htonl的MSDN中提到了,使用该函数可以将一个本地字节序的IP地址转换成网络字节序的IP地址,但是不会检查作为输入参数的IP地址的合法性。字节序转换函数的使用,不依赖于WSAStart来初始化网络库。还有就是不要想多了,这是Windows网络库中的函数,这里的htonl就是完全的等价于将小端字节序转换成大端字节序,没有什么额外的其他处理。

字节序转换可以不生硬

看完上文小节中的中大小端字节序转换的例子,我不知道你想到了什么。我想到的是,如果 Message 不是只有4个待转换的多多字节字段,而是有10个,或者,还有Message2…Message50需要做类似的转换,呃呃呃,你会不会被搞得头大? 不禁要问,难道跨平台的大小端字节序转换,只能是逐个消息结构,逐个结构字段,如此生硬的进行转化? 显然那不可能!我们简单聊聊这个事情。

前文已经讨论过,在有些情况下可以不去进行字节序转换,有的时候必须要进行,这两种状态的大前提都是得有需要进行字节序转换的多字节数据。说到这里,就想到了围魏救赵解决字节序问题的一个思路,即,消除待传输信息中的多字节数据。这里的消除,可以是真正的消除,如传输结构中只使用字节数组,当然这不太现实;也可以是像文本文件加BOM的方式那样,显式的标记出传输的文件/字节流是大端还是小端字节序的。不过讲真的,好像很难回避啊?消息数据都是单字节,不靠谱。即使是文本文件,也必须要考虑多字节编码情况下的大小端问题。
如,HTTP消息是以文本形式传输的,通常使用ASCII编码或UTF-8编码。UTF-8 编码使用 1-4个字节来表示每个字符,当时多字节时,就要考虑大小端问题。我们就着文本文件编码这个事情,稍微深入下:

文本文件的字节序标记
在 MSDN 中还发现了 Using Byte Order Marks 这篇文章,一起写在这里,进一步加深对字节序的理解,并不打算具体深入展开。
始终为 Unicode 纯文本文件添加字节顺序标记的前缀(BOM),以告知接收文件的应用程序该文件的字节序。如此一来,传输此文件时,就不用关心其字节序了,由接收端按照BOM标记自行处理。必须先要理解的是,所谓文本文件,其中存储的并不是可见字符,而是字符的编码值,文本编辑器或其他应用程序替我们完成了字符编码值和可见字符之间的转换。文本文件的内容就是一串数字编码,比如ASCII编码或者Unicode编码。文本编辑器会根据文件中的编码值,查找对应的字形并显示出来。
在这里插入图片描述
如果文件编码是UTF-32,则每个文本字符都使用4个字节表示,将所有编码显示为可见字符,这很好理解。使用 UTF-32 编码可以简化一些字符处理操作,但是它占用更多的存储空间。实际应用中,UTF-8 和 UTF-16 通常是更常见和推荐的 Unicode 编码方式,如微软使用的就是UTF16 编码,小端字节序。UTF-8 编码使用 1-4个字节来表示每个字符。UTF-16 编码使用 2 个字节或 4 个字节来表示每个字符。以UFT-8为例,它是如何知道,读取到1个字节后,就可以翻译成可见字符,而不是再读取下一个字节,联合成两个字节后再一起翻译成一个可见字符?时间有限,这个放在后续发布的字符串和字符编码的博文中继续讨论和讲述。

字节序和位序

这节内容,本不该写在这里,但是写着写着就契合啦。
以太网协议规定了数据的字节传输顺序,但并没有规定数据的位传输顺序。与之不同的是,CAN协议本身并没有规定字节发送顺序,它只规定了数据的位传输顺序(bit ordering),即 MSb First。关于字节序和位序的其他诸多问题,可参考《存储和传输/大小端字节序概念、决定因素、给编程带来的困扰》、《存储和传输/探究普通结构和位域结构体数据在内存中的字节对齐规》、《语言基础/分析和实践 C&C++ 位域结构数据类型》、《网络通信/协议栈内网络字节序与主机字节序的转换实现》等文章,这里不再赘述。

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

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

相关文章

并查集+思维,CF 1039C - Network Safety

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1039C - Network Safety 二、解题报告 1、思路分析 考虑边<u, v>&…

深度学习基础—动量梯度下降法

1.算法原理 动量梯度下降法就是在梯度下降法的基础上&#xff0c;使用指数加权移动平均值&#xff0c;来平均梯度&#xff0c;这种算法比梯度下降法更快。 如上图&#xff0c;损失函数的最小值是红点&#xff0c;椭圆是损失函数的图像&#xff0c;梯度下降法就像蓝线和紫线&…

Linux安装MQTT 服务器(图文教程)

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息传输协议&#xff0c;专为低带宽和不稳定的网络环境设计&#xff0c;非常适合物联网&#xff08;IoT&#xff09;应用。 官网地址&#xff1a;https://www.emqx.com/ 一、版本选择 根据自己…

el-tree多选的父子关联和父子不关联和拖拽功能

公用js变量&#xff1a; data () {return {// 绑定的数组treeData: [],// 多选选择的idids: []} }, 公用js方法&#xff1a; /*** 选择多选改变*/ nodeChange(data, checked, indeterminate) {let keys this.$refs.treeCategory.getCheckedKeys();this.ids keys; } 第一种…

Android 架构模式之 MVP

目录 架构设计的目的对 MVP 的理解代码ModelViewPresenter Android 中 MVP 的问题试吃个小李子ModelViewPresenter 大家好&#xff01; 作为 Android 程序猿&#xff0c;你有研究过 MVP 架构吗&#xff1f;在开始接触 Android 那一刻起&#xff0c;我们就开始接触 MVC 架构&am…

“解决Windows电脑无法投影到其他屏幕的问题:尝试更新驱动程序或更换视频卡“

背景: 今天在日常的工作中&#xff0c; 我想将笔记本分屏到另一个显示屏&#xff0c;我这电脑Windows10&#xff0c;当我按下Windows键P键&#xff0c;提示我"你的电脑不能投影到其他屏幕&#xff0c;请尝试从新安装驱动程序或使用"遇到这种问题。 解决方法1: 1.快…

解决 idea 创建maven项目卡住

一, 现象 选择一个Archetype后创建项目,一直卡着,点哪里都点不了,有的博客说可以看maven的日志排查问题,我这里没有任何日志输出 二,为什么会卡住 结论: 因为idea在从中央仓库下载archetype-catalog.xml(文件较大,14.8M)导致卡住 分析: 首先要明白通过Archetype创建…

openssl查看证书公钥 openssl 验证证书和密钥

例如&#xff1a;中间件或者openssl生成国密证书请求文件文件里面省份必须写陕西省三个汉字 安装完成后&#xff0c;使用下列命令查看该版本的openssl是否支持SM2参数&#xff1a; openssl ecparam -list_curves | grep SM2 查看openssl版本信息 openssl version -a 查看open…

【C++篇】迈入新世界的大门——初识C++(下篇)

文章目录 前言引用引用的概念和定义引用的特性引用的使用const引用指针和引用的关系 inline#define定义宏inline nullptr 前言 接上篇&#xff1a;【C篇】迈入新世界的大门——初识C&#xff08;上篇&#xff09; 引用 引用的概念和定义 引⽤不是新定义⼀个变量&#xff0c;…

第10章 无持久存储的文件系统 (3)

目录 10.2 简单文件系统 10.2.1 顺序文件 10.2.2 用libfs编写文件系统 10.2.3 调试文件系统 10.2.4 伪文件系统 10.3 sysfs 10.3.1 概述 10.3.2 数据结构 10.3.3 装载文件系统 10.3.4 文件和目录操作 10.3.5 向sysfs添加内容 10.4 小结 本专栏文章将有70篇左右&…

Node.js及mysql的安装,建立页面,javascript对mySQL数据库的操作过程

具体动态效果看视频 node.js连接MySQL数据库操作 第一部分&#xff1b;配置服务器环境 Nods.js, NPM,CNPM,mysql2,express的安装 前往 Node.js 官方网站&#xff08;https://nodejs.org/&#xff09;下载并安装最新的稳定版本&#xff0c;确定配置好path环境变量&#xff0c;其…

Linux网络环境搭建,开发板网线直连电脑网口,电脑WIFI上网

开发板网线直连电脑网口&#xff08;电脑自带&#xff0c;一般有PCI&#xff0c;不是USB网卡&#xff09;&#xff0c;电脑WIFI上网 因为电脑是 WiFi 上网&#xff0c;所以需要添加一个网络适配器并设置成 NAT 模式&#xff0c;供虚拟机上网。 设置双网卡&#xff0c;注意双网卡…

SQL 时间盲注 (injection 第十五关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&#x…

visual studio使用技巧:快速生成Json、XML对应类

visual studio快速生成Json、XML对应类 在项目中经常用到json或者xml作为配置文件&#xff0c;进行序列化和反序列化就需要有对应的类&#xff0c;重新写一遍类就比较麻烦&#xff0c;这里就讲一下通过visual studio快速生成json或者xml对应类型的方法。 自动生成Json类 复制…

大数据-90 Spark 集群 RDD 编程-高阶 RDD容错机制、RDD的分区、自定义分区器(Scala编写)、RDD创建方式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

【Python】AttributeError: module ‘PIL.Image‘ has no attribute ‘ANTIALIAS‘

【Python】成功解决AttributeError: module ‘PIL.Image‘ has no attribute ‘ANTIALIAS‘ 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博…

MySQL集群+Keepalived实现高可用部署

Mysql高可用集群-双主双活-myqlkeeplived 一、特殊情况 常见案例&#xff1a;当生产环境中&#xff0c;当应用服务使用了mysql-1连接信息&#xff0c;在升级打包过程中或者有高频的数据持续写入【对数据一致性要求比较高的场景】&#xff0c;这种情况下&#xff0c;数据库连接…

STM32之继电器与震动传感器的使用,实现震动灯

在STM32的外设应用中&#xff0c;继电器扮演着重要的角色。继电器作为一种电控制器件&#xff0c;其主要作用是通过小电流控制大电流的通断&#xff0c;实现电路的自动控制和保护。具体来说&#xff0c;继电器在STM32外设中的作用可以归纳为以下几点&#xff1a; 电路隔离与保…

在线学习考试设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图详细视频演示技术栈系统测试为什么选择我官方认证玩家&#xff0c;服务很多代码文档&#xff0c;百分百好评&#xff0c;战绩可查&#xff01;&#xff01;入职于互联网大厂&#xff0c;可以交流&#xff0c;共同进步。有保障的售后 代码参考数据库参…

“CSS”第一步——WEB开发系列13

CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档&#xff08;如 HTML 文档或 XML 应用&#xff09;添加样式&#xff08;字体、间距和颜色等&#xff09;的计算机语言&#xff0c;CSS 文件扩展名为 .css。 一、什么是 CSS&a…