Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面经及项目开发之网络编程核心概念:大端与小端

面经及项目开发之网络编程核心概念:大端与小端

作者头像
公众号guangcity
发布于 2019-09-20 09:38:29
发布于 2019-09-20 09:38:29
1.3K00
代码可运行
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)
运行总次数:0
代码可运行

面经及项目开发之网络编程核心概念:大端与小端

0.导语

最近做的项目都涉及了协议,网络编程,针对协议与网络通信数据传输,大家使用抓包工具抓出来的数据例如:0x5634... 这些就是所谓的网络字节序,俗称大端!而针对不同的机器,有着不同的模式,有些是大端,有些是小端,如果在网络传输中发送的是原数据0x3456,而不是0x5634,那么会发生灾难性的错误,因此需要在发送前调用htons或者htonl函数将其转换为大端模式,也就是网络字节序,相信在深入理解一些开源的项目中,底层用C/C++ 写的程序中,大家会看到这些函数。

另外,在面试过程中,这个点也非常的重要,通常会考察这些概念与碰到的问题之类的,那么下面一起来从零学起。

简化一下需求:

(1)WORD类型传输约定:先传递高八位,再传递低八位。

(2)DWORD传递约定:先传递高24位,然后传递高16位,再传递高八位,最后传递低八位

针对这样的类型如何传输呢?

下面看完本篇文章就知道怎么传输了!

1.What?

所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

简单来说:大端——高尾端,小端——低尾端。

实际例子如下:

16bit宽的数0x1234在Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x6411开始存放)为:

内存地址

小端模式存放内容

大端模式存放内容

0x6410

0x34

0x12

0x6411

0x12

0x34

32bit宽的数0x12345678在Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x6411开始存放)为:

内存地址

小端模式存放内容

大端模式存放内容

0x6410

0x78

0x12

0x6411

0x56

0x34

0x6412

0x34

0x56

0x6413

0x12

0x78

2.How?

上面阐述了如何判断大端与小端,那如何来判断自己的CPU是大端还是小端。

下面给出了两种方法。

方法1:使用联合体,给一个变量赋值,使用另一个变量查看低地址存储的是高位还是低位。

方法2:直接查看char的低地址存储的是高位还是低位。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 检查机器的字节序
 * @return
 */
bool isBigEndian() {
    // 使用联合体
    union node {
        int num;
        char ch;
    };
    union node p;
    //方法一
    p.num = 0x12345678;
    // 低位地址存储低位
    if (p.ch == 0x78) {
        printf("Little endian\n");
    } else {
        // 低位地址存储高位
        printf("Big endian\n");
    }
    //方法二
    int num = 0x12345678;
    char *q = (char *)#
    if (*q == 0x78) {
        printf("Little endian\n");
    } else {
        printf("Big endian\n");
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
=========两种方式验证机器大端还是小端==========
Little endian
Little endian

3.实现

那如何自己实现小端转大端(网络字节序列)呢?

分为两种,一种是16位,一种是32位。

针对16位,实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 低地址存放高位,高地址存放低位
 * WORD类型传输约定:先传递高八位,再传递低八位。
 * 其中WORD 被定义为uint16_t
 * 2字节大端转换函数
 * @param value
 * @param buf
 * @return
 */
WORD EndianSwap16(const WORD &value, unsigned char* buf = NULL) {
    assert(sizeof(value) == 2);
    if(buf) {
        *buf++ = value&0x00ff;
        *buf = (value&0xff00)>>8;
    }
    return (value&0x00ff)<<8|(value&0xff00)>>8;
}

其中buf存储的是大端的每一个字节。

调用上述函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cout<<"==========调用自己实现的函数实现小端转换为大端=========="<<endl;
uint16_t a = 0x1234;
unsigned char buf[2];
printf("16位小端--->大端:%x\n", EndianSwap16(a, buf));

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==========调用自己实现的函数实现小端转换为大端==========
16位小端--->大端:3412
34 12

针对32位:实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 低地址存放高位,高地址存放低位
 * DWORD传递约定:先传递高24位,然后传递高16位,再传递高八位,最后传递低八位
 * 4字节大端转换函数
 * 其中DWORD 被定义为uint32_t
 * @param value
 * @param buf
 * @return
 */
DWORD EndianSwap32(const DWORD &value, unsigned char* buf=NULL) {
    assert(sizeof(value) == 4);
    if(buf) {
        *buf++ = value&0x000000ff;
        *buf++ = (value&0x0000ff00)>>8;
        *buf++ = (value&0x00ff0000)>>16;
        *buf = value>>24;
    }
    return ((value >> 24) |
            ((value & 0x00ff0000) >> 8) |
            ((value & 0x0000ff00) << 8) |
            (value << 24));
}

其中buf存储的是大端的每一个字节。

调用上述函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint32_t b = 0x12345678;
unsigned char buf1[4];
printf("32位小端--->大端:%x\n", EndianSwap32(b, buf1));
printf("%x %x %x %x\n", buf1[0], buf1[1], buf1[2], buf1[3]);

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==================================================
32位小端--->大端:78563412
78 56 34 12

4.调用函数

在C/C++网络开发中可以通过引入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <netinet/in.h>

调用htonlhtonsntohlntohs来完成小端与大端转换。

那么下面来使用一下,使用之前先阐述一下这几个函数:

  • htonl()

32位无符号整型的主机字节顺序到网络字节顺序的转换(小端->大端)

  • htons()

16位无符号短整型的主机字节顺序到网络字节顺序的转换 (小端->大端)

  • ntohl()

32位无符号整型的网络字节顺序到主机字节顺序的转换 (大端->小端)

  • ntohs()

16位无符号短整型的网络字节顺序到主机字节顺序的转换 (大端->小端)

注,主机字节顺序,X86一般多为小端(little-endian),网络字节顺序,即大端(big-endian);

调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cout<<"==========htonl htons ntohl ntohs函数调用=========="<<endl;
printf("16位小端--->大端:%x\n",htons(a));
printf("32位小端--->大端:%x\n",htonl(b));

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==========htonl htons ntohl ntohs函数调用==========
16位小端--->大端:3412
32位小端--->大端:78563412
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C语言-- 大端小端详解
16bit宽的数0x1234在Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:
用户3479834
2021/02/03
5K0
【网络编程系列】一:字节顺序的大端与小端表示法
一、字节序 字节序,也就是字节的顺序,指的是多字节的数据在内存中的存放顺序。 在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如:如果C/C++中的一个int型变量 a 的起始地址是&a = 0x100,那么 a 的四个字节将被存储在存储器的0x100, 0x101,0x102, 0x103位置。 根据整数 a 在连续的 4 byte 内存中的存储顺序,字节序被分为大端序(Big Endian) 与 小端序(Little Endian)两类。 然后就牵涉出两大CPU派系: Motorola 68
老白
2018/03/19
1.9K0
【网络编程系列】一:字节顺序的大端与小端表示法
网络编程之大小端
假设unsigned int num = 0x12345678,内存起始位置为0x4000,则在内存中的存放顺序为:
动动我试试
2020/03/12
6810
网络编程中的大小端
在计算机领域,大小端(Endianness)是指字节序的排列顺序。简单来说,就是存储器中多字节数据的字节序列,从高到低或从低到高的顺序不同。那么,何谓大小端呢?
李述铜
2023/05/01
8690
网络字节序与主机字节序转换
在Linux网络编程中,经常碰到网络字节序与主机字节序的相互转换。说到网络字节序与主机字节序需要清晰了解以下几个概念。
恋喵大鲤鱼
2018/08/03
5.6K0
网络字节序与主机字节序转换
IP地址的三种表示格式及在Socket编程中的应用
使用TCP/IP协议进行网络应用开发的朋友首先要面对的就是对IP地址信息的处理。IP地址其实有三种不同的表示格式:
黄规速
2022/04/14
2.6K0
IP地址的三种表示格式及在Socket编程中的应用
网络编程基础第二讲.网络编程框架
     socket 是开发接口.是TCP/IP网络环境下.应用程序与驱动程序之间访问的接口.
IBinary
2019/05/25
5590
网络编程打开的第一节预备课-----关于socket
传统的进程间通信借助内核提供的 IPC 机制进行, 但是只能限于本机通信, 若 要跨机通信, 就必须使用网络通信,比如之前在操作系统学习到的pipe通信,这是一个本机通信,是最基本的IPC机制进行的。
莫浅子
2023/11/09
1880
网络编程打开的第一节预备课-----关于socket
分享一篇关于 C# 高低字节转换的问题
常用单片机内存一个地址只能存八位二进制数,最大数据只能是255(十进制). 当需要储存大于255的数据时,就需要用两个以上的内存地址,低位字节中的数是原数,高位字节中的数要乘以位数再与低位字节中的数相加才是你真要的数.
用户7053485
2021/01/29
2.8K0
字节序(大小端)详解从高低地址和高低位开始理解【转】
http://blog.csdn.net/jk110333/article/details/44137423
保持热爱奔赴山海
2019/09/17
7.9K0
谈一谈字节序的问题
字节序关系到我们的网络数据能否被正确地解析或使用。那么什么是字节序?又怎么处理字节序的问题呢?本文就来谈一谈字节序的问题。
编程珠玑
2019/09/03
8460
谈一谈字节序的问题
清晰讲解LSB、MSB和大小端模式及网络字节序
今天在做需求的涉及到一个固件版本的概念,其中固件组的人谈到了版本号从MSB到LSB排列,检索查阅后将所得整理如下。
翎野君
2023/05/12
6.4K0
清晰讲解LSB、MSB和大小端模式及网络字节序
【答疑解惑】什么是大小端
首先一个问题,大小端是如何来的? 我们知道,在计算机系统中,内存是以字节为单位的,一个地址对应一个字节,一个字节8bit,那么数据类型比如int,short,long等在内存中肯定不止占用一个字节,这就涉及到数据的存放方式,是数据的高位字节放到高地址呢,还是数据的高位字节放在低地址呢?而这两种不同的组织方式就叫大小端。 所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数
程序员互动联盟
2018/03/14
9760
linux网络编程系列(二)
套接字,也叫socket,是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。网络通信,说白了就是进程间的通信(同一台机器上不同进程或者不同计算机上的进程间通信)。
cpp加油站
2021/04/16
9550
TCP/IP网络编程-前三章学习笔记
前两年, 就买了《TCP/IP网络编程》这本书, 由于自身基础薄弱, 只是走马观花翻阅了几张。
用户2825413
2019/07/16
7840
TCP/IP网络编程-前三章学习笔记
《编程千问》第七问:你了解大端和小端字节序吗?
大端(Big Endian) 和 小端(Little Endian) 是计算机中数据存储的两种字节序方式。它们主要描述多字节数据(如整型、浮点型)在内存中的存储顺序。
码事漫谈
2024/12/20
3740
【编程基础】简单理解大小端那些事儿
什么是计算机大小端?简单来说,大小端(Endian)是指数据存储或者传输时的字节序,大小端分大端和小端。 所谓大端(Big-Endian)模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放。 所谓小端(Little-Endian)模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部
程序员互动联盟
2018/03/13
2K0
【编程基础】简单理解大小端那些事儿
机器大小端存储模式
一开始是由于不同架构的CPU处理多个字节数据的顺序不一样,比如x86的是小段模式,KEIL C51是大端模式。但是后来互联网流行,TCP/IP协议规定为大端模式,为了跨平台通信,还专门出了网络字节序和主机字节序之间的转换接口(ntohs、htons、ntohl、htonl)
用户11029129
2024/06/04
1770
机器大小端存储模式
Socket编程实践(1) 基本概念
1. 什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口。TCP/IP协议的底层部分已经被内核实现了,而应用层是用户需要实现的,这部分程序工作在用户空间。用户空间的程序需要通过套接字来访问内核网络协议栈。 套接口是全双工的通信,它不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。 套接字还可以异构系统间进行通信,异构系统指的是在硬件或软件上有所差别的系统,例如安卓系统的手机与windows系统的PC机上都可以实现QQ通信,套接字可以实现在这两个设备上的通信。 2.
Tencent JCoder
2018/07/02
5820
[c语言日寄]内存初阶:大端字节序和小端字节序
今天给大家带来的是大端字节序(Big Endian)和小端字节序(Little Endian)题目,它们在硬件层面、网络通信、编程语言和数据存储都有涉及。
siy2333
2025/02/05
2220
推荐阅读
相关推荐
C语言-- 大端小端详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验