網路通訊時位元組序轉換原理與網路位元組序、大端和小端模式
引言:在進行網路通訊時是否需要進行位元組序轉換?
相同位元組序的平臺在進行網路通訊時可以不進行位元組序轉換,但是跨平臺進行網路資料通訊時必須進行位元組序轉換。
原因如下:網路協議規定接收到得第一個位元組是高位元組,存放到低地址,所以傳送時會首先去低地址取資料的高位元組。小端模式的多位元組資料在存放時,低地址存放的是低位元組,而被髮送方網路協議函式傳送時會首先去低地址取資料(想要取高位元組,真正取得是低位元組),接收方網路協議函式接收時會將接收到的第一個位元組存放到低地址(想要接收高位元組,真正接收的是低位元組),所以最後雙方都正確的收發了資料。而相同平臺進行通訊時,如果雙方都進行轉換最後雖然能夠正確收發資料,但是所做的轉換是沒有意義的,造成資源的浪費。而不同平臺進行通訊時必須進行轉換,不轉換會造成錯誤的收發資料,位元組序轉換函式會根據當前平臺的儲存模式做出相應正確的轉換,如果當前平臺是大端,則直接返回不進行轉換,如果當前平臺是小端,會將接收到得網路位元組序進行轉換。
下面對一些概念做下介紹:
一、大端、小端
"大端"和"小端"表示多位元組值的哪一端儲存在該值的起始地址處;小端儲存在起始地址處,即是小端位元組序;大端儲存在起始地址處,即是大端位元組序;
或者說:
1.小端法(Little-Endian)就是低位位元組排放在記憶體的低地址端(即該值的起始地址),高位位元組排放在記憶體的高地址端;
2.大端法(Big-Endian)就是高位位元組排放在記憶體的低地址端(即該值的起始地址),低位位元組排放在記憶體的高地址端;
舉個簡單的例子,對於整型資料0x12345678,它在大端法和小端法的系統中,各自的存放方式如下圖1所示:
二、網路位元組序
網路上傳輸的資料都是位元組流,對於一個多位元組數值,在進行網路傳輸的時候,先傳遞哪個位元組?也就是說,當接收端收到第一個位元組的時候,它將這個位元組作為高位位元組還是低位位元組處理,是一個比較有意義的問題;
UDP/TCP/IP協議規定:把接收到的第一個位元組當作高位位元組看待,這就要求傳送端傳送的第一個位元組是高位位元組;而在傳送端傳送資料時,傳送的第一個位元組是該數值在記憶體中的起始地址處對應的那個位元組,也就是說,該數值在記憶體中的起始地址處對應的那個位元組就是要傳送的第一個高位位元組(即:高位位元組存放在低地址處);由此可見,多位元組數值在傳送之前,在記憶體中因該是以大端法存放的;
所以說,網路位元組序是大端位元組序;
比如,我們經過網路傳送整型數值0x12345678時,在80X86平臺中,它是以小端發存放的,在傳送之前需要使用系統提供的位元組序轉換函式htonl()將其轉換成大端法存放的數值;如下圖2所示:
三、位元組序測試
不同CPU平臺上位元組序通常也不一樣,下面這個簡單的程式碼可以測試不同平臺上的位元組序:
#include <stdio.h>
#include <netinet/in.h>
int main(int argc,char** argv)
{
int num = 0x12345678;
unsigned char* pc = (unsigned char*)(&num);
printf("local order:\n");
printf("[0]: 0x%X addr:%u\n", pc[0], &pc[0]);
printf("[1]: 0x%X addr:%u\n", pc[1], &pc[1]);
printf("[2]: 0x%X addr:%u\n", pc[2], &pc[2]);
printf("[3]: 0x%X addr:%u\n", pc[3], &pc[3]);
num = htonl(num);
printf("htonl order:\n");
printf("[0]: 0x%X addr:%u\n", pc[0], &pc[0]);
printf("[1]: 0x%X addr:%u\n", pc[1], &pc[1]);
printf("[2]: 0x%X addr:%u\n", pc[2], &pc[2]);
printf("[3]: 0x%X addr:%u\n", pc[3], &pc[3]);
return 0;
}
SPARC平臺上的輸出:
local order:
[0]: 0x12 addr:4290770212 //高位位元組存放在低地址處,則是大端法;
[1]: 0x34 addr:4290770213
[2]: 0x56 addr:4290770214
[3]: 0x78 addr:4290770215 //低位位元組存放在高地址處;
htonl order:
[0]: 0x12 addr:4290770212 //由此看出,主機位元組序與網路位元組一樣;
[1]: 0x34 addr:4290770213
[2]: 0x56 addr:4290770214
[3]: 0x78 addr:4290770215
X86平臺上的輸出:
local order:
[0]: 0x78 addr:4289157020 //低位位元組存放在低地址處,則是小端法;
[1]: 0x56 addr:4289157021
[2]: 0x34 addr:4289157022
[3]: 0x12 addr:4289157023 //高位位元組存放在高地址處;
htonl order:
[0]: 0x12 addr:4289157020 //由此看出,主機位元組序與網路位元組不一樣;
[1]: 0x34 addr:4289157021
[2]: 0x56 addr:4289157022
[3]: 0x78 addr:4289157023
INTEL平臺上的輸出:
local order:
[0]: 0x78 addr:1245044 //低位位元組存放在低地址處,則是小端法;
[1]: 0x56 addr:1245045
[2]: 0x34 addr:1245046
[3]: 0x12 addr:1245047 //高位位元組存放在高地址處;
htonl order:
[0]: 0x12 addr:1245044 //由此看出,主機位元組序與網路位元組不一樣;
[1]: 0x34 addr:1245045
[2]: 0x56 addr:1245046
[3]: 0x78 addr:1245047
相關文章
- 大端序、小端序、網路位元組序
- c# 主機和網路位元組序的轉換 關於網路位元組序和主機位元組序的轉換C#
- 第五篇:主機位元組序與網路位元組序的轉換
- 分享:大端小端-位元組儲存順序
- modbus和位元組序
- 理解位元組序
- 網路通訊1:位元組流的封裝封裝
- Android與物聯網裝置通訊-自定義報文與位元組序Android
- Qt 大小端位元組序的處理QT
- 擴充理解位元組序
- Modbus通訊協議中的四種位元組順序協議
- C++與Qt的位元組序探究:C++QT
- C# 中大端序與小端序C#
- golang之大端序、小端序Golang
- 深入理解Emoji(二) —— 位元組序和BOM
- Android與物聯網裝置通訊 - 位元組報文組裝與解析Android
- oracle小知識點13--rman convert轉換表空間位元組順序Oracle
- 位元組編碼轉換
- RMAN跨小版本跨平臺與位元組序傳輸表空間
- C#位元組陣列與字串轉換C#陣列字串
- 一個位元組的網路漫遊故事獨白
- Rust 中的位元組序、API 設計和多型性 - JimmyRustAPI多型
- nodejs字元與位元組之間的轉換NodeJS字元
- 位元組跳動在 Go 網路庫上的實踐Go
- 獨家!位元組跳動網路小貸增資至50億,董事長、總經理換帥
- 用抓包工具本地檢視位元組序問題!!
- 異構OS平臺的不同點 - 位元組順序
- 16進位制資料發生高位位元組和地位位元組互換
- 網際網路寒冬!騰訊、位元組跳動面經已發,系列篇
- 從 unicode 到位元組的轉換Unicode
- 位元組對齊小談
- 極客世界 極致位元組 — Byte CTF 位元組跳動網路安全攻防大賽即將打響
- nodejs圖片轉換位元組儲存NodeJS
- 位元組碼引用檢測原理與實戰
- C語言基礎 告知當前機器的位元組序C語言
- 位元組投資AI設計服務提供商設序科技AI
- C#結構體和位元組陣列的轉換C#結構體陣列
- 雙非本科拿到阿里騰訊位元組,分享Java後端路線阿里Java後端