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

文章目录

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

概述

本文主要讲述了在哪些场景下必须要进行大小端字节序转换,在哪些场景下可以不用进行大小端字节序转换,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.rhkb.cn/news/404618.html

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

相关文章

基础第3关:LangGPT结构化提示词编写实践

提示词&#xff1a; # Role: 伟大的数学家 ## Profile - author: LangGPT - version: 1.0 - language: 中文 - description: 一个伟大的数学家&#xff0c;能够解决任何的数学难题 ## Goals: 根据关键词进行描述&#xff0c;避免与已有描述重复。 ## Background: 你正在被…

基于Java语言的高能耗企业 水-电-气-热-油等数据采集系统-能源管理系统-源码

基于Java语言的高能耗企业 水-电-气-热-油-空压机等数据采集系统-能源管理系统-在线监测系统 场景介绍 介绍 适用于建筑、工厂、商场、医院、园区、高耗能企业、城市双碳建设平台等的水、电、气、热、油等能源数据采集、加工、分析、预警、碳指标、碳排放计算等场景&#xff…

Mysql(三)---增删查改(基础)

文章目录 前言1.补充1.修改表名1.2.修改列名1.3.修改列类型1.4.增加新列1.5.删除指定列 2.CRUD3.新增(Create)3.1.单行插入3.2.指定列插入3.3.多行插入 4.数据库的约束4.1.约束的分类4.2.NULL约束4.3.Unique约束4.4.Default 默认值约束4.5.PRIMARY KEY&#xff1a;主键约束4.6.…

指挥中心控制台如何选择合适的定制厂家

在构建高效、安全的指挥中心过程中&#xff0c;选择一家合适的控制台定制厂家至关重要。控制台作为指挥中心的核心组成部分&#xff0c;不仅承载着设备集成、信息显示的重任&#xff0c;还直接关系到操作人员的舒适度和工作效率。因此&#xff0c;在挑选定制厂家时&#xff0c;…

Flask详细教程

1、Flask是什么&#xff1f; Flask是一个非常小的PythonWeb框架&#xff0c;被称为微型框架&#xff08;类似Java的SpringBoot&#xff09;&#xff1b;只提供了一个稳健的核心&#xff0c;其他功能全部是通过扩展实现的&#xff1b;意思就是我们可以根据项目的需要量身定制&a…

介绍 Kettle 的 Spoon 图形化界面工具

Kettle Spoon 集成开发环境工具启动后&#xff0c;弹出 Welcome 的欢迎页面 目录 一、界面构成二、菜单说明1. 【文件(F)】菜单2. 【编辑】菜单3. 【视图】菜单4. 【执行】菜单5. 【工具】菜单6. 【帮助】菜单7. 转换工程快捷菜单图标8. 任务工程快捷菜单图标 一、界面构成 &…

使用百度文心智能体创建AI旅游助手

百度文心智能体平台为你开启。百度文心智能体平台&#xff0c;创建属于自己的智能体应用。百度文心智能体平台是百度旗下的智能AI平台&#xff0c;集成了先进的自然语言处理技术和人工智能技术&#xff0c;可以用来创建属于自己的智能体应用&#xff0c;访问官网链接&#xff1…

【JPCS独立出版,EI稳定检索】2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024,9月27-29)

2024年工业机器人与先进制造技术国际学术会议&#xff08;IRAMT 2024&#xff09;将于2024年9月27-29日在中国成都举办。 此次会议将围绕工业机器人、机电技术、机械及制造等领域的最新研究成果展开讨论&#xff0c;并广泛邀请了国内外领域内的著名专家与学者。会议旨在搭建一个…

[linux#39][线程] 详解线程的概念

线程&#xff1a;是进程内的一个执行分支。线程的执行粒度比进程要细 什么是线程&#xff1f; • 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程 是“一个进程内部的控制序列” • 一切进程至少都有一个执行线程 • …

基于SpringBoot的Java个人博客系统的设计与实现(源码+lw+部署文档+讲解等)

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

原生HTML5、CSS、JavaScript实现简易网易云音乐播放

1.效果图 2.源码 1.index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>网易云音乐</title><link rel"stylesheet" href"../CSS/index.css"> </head>…

最小路径和[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个包含非负整数的m x n网格grid&#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;每次只能向下或者向右移动一步。 示例 1&#xff1a; 输入&#xff1a;grid [[…

新智元 | 百万在线,大圣归来!《黑神话:悟空》石破天惊,RTX 4090D飞越花果山

本文来源公众号“新智元”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;百万在线&#xff0c;大圣归来&#xff01;《黑神话&#xff1a;悟空》石破天惊&#xff0c;RTX 4090D飞越花果山 【新智元导读】等待四年&#xff0c;《黑…

Java常用集合(List、Map)类型相关问题整理

一、背景 针对Java基础集合的部分&#xff0c;对一些常见的问题进行整理&#xff0c;方便后续能够随时复习 二、问题与回答 &#xff08;1&#xff09;Java集合类ArrayList初始化时数组的默认长度是多少&#xff1f; 答&#xff1a;在new ArrayList() 这段代码执行完后&a…

软件测试基础入门

一、基础概念 什么是软件&#xff1a;控制计算机硬件的工具&#xff0c;操作系统软件、应用软件 软件基本组成&#xff1a;客户端、服务器、数据库 软件产生过程&#xff1a;需求构思--> 需求文档 -->UI/UE -- >产品研发 -->产品测试 -- >部署上线 什么是软…

web实现drag拖拽布局

这种拖拽布局功能其实在电脑操作系统或者桌面应用里面是经常使用的基础功能&#xff0c;只是有时候在进行web开发的时候&#xff0c;对这个功能需求量不够明显&#xff0c;但却是很好用&#xff0c;也很实用。能够让用户自己拖拽布局&#xff0c;方便查看某个区域更多内容&…

关于#vscode#的问题:把软件卸载不会再出现蓝屏

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

ViT篇外:NVIDIA Llama-3.1-Minitron 4B

相关阅读&#xff1a; ViT&#xff1a;3 Compact Architecture MobileLLM&#xff1a;“苗条”的模型比较好&#xff01; 大家也许会很好奇为什么在ViT章节插入了NVIDIA Llama-3.1-Minitron 4B&#xff0c;ViT因为应用场景的特殊性所以都寄希望于高效率的模型&#xff0c;因…

搭建内网开发环境(二)|Nexus安装及使用

引言 上一篇教程中按照了 docker 作为容器化工具&#xff0c;在本篇教程中将使用 docker-compose 安装 nexus。 搭建内网开发环境&#xff08;一&#xff09;&#xff5c;基于docker快速部署开发环境 什么是 Nexus Nexus是一个强大的仓库管理器&#xff0c;主要用于搭建和管…

【论文阅读】SegNeXt:重新思考卷积注意力设计

《SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation》 原文&#xff1a;https://github.com/Visual-Attention-Network/SegNeXt/blob/main/resources/paper.pdf 源码&#xff1a;https://github.com/Visual-Attention-Network/SegNeXt 1、简介 …