关于socket通信中大小端转换问题
本人一直有个疑惑,大小端通信怎么存储(以前一直知道这个概念,但怎么都跟实际匹配不上,网络上也并没有说怎么处理大小端通信问题)
socket通信中 addr 需要转换成网络字节序,也就是大端
助记: htonl h-> host 缩写 n -> net 缩写 l 是类型缩写(l -> long ll-> longlong s short 都是无符号的)
首先理解下,大小端 数据在内存的存储顺序不同,注意数据还是那个数据,只是存储的方式不同。
大端,数据的低位在内存的高位
小端,数据的低位在内存的低位
内存地址是按字节排序的 0x01 0x02 每个地址偏移是一个字节的内容。
数据 0x12345678 数据的从低到高 0x78 0x56 0x34 0x12.
大端 内存内数据 0x01-0x12 0x02-0x34 0x03-0x56 0x04-0x78
小端 内存内数据 0x01-0x78 0x02-0x56 0x03-0x34 0x04-0x12
socket传输的是字节流,byte[] 数组,我们分两种情况讨论 unsigned int var=0x12345678; 在网络中的传输状态。
1.两端 大小端 一致,则直接使用memcpy就可以,memcpy是内存数据的 大端会变成 0x12345678 数据传输到对端,把数据copy到内存中也是 0x12345678, 小端是 0x78563412, copy 到本地 也是这个值,毫无影响。
2.两端 大小端 不一致,变成byte数据的时候,memcpy是内存数据的 大端会变成 0x12345678 数据传输到对端,把数据copy到内存中也是 0x12345678, 这时cpu按内存地址认为值的话, 并不等于 数据0x12345678. 所以解析错误。小端同理。
解决办法,所以在socket传输多字节数据的情况下,需要把内存数据转为数据顺序(自定义的,可以从高到低,也可以从低到高,但是发送端和解析端必须一致)
比如说
void writeInt32(int v) { char buf[4] = {}; buf[0] = (v >> 24) & 0xFF; buf[1] = (v >> 16) & 0xFF; buf[2] = (v >> 8) & 0xFF; buf[3] = (v >> 0) & 0xFF; }
int readInt32(char[] buf) { int ch1 = buf[0]; int ch2 = buf[1]; int ch3 = buf[2]; int ch4 = buf[3]; return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); }
上述这样操作,即可解决对应的字节流传输大小端问题。
题话外:
java 的数据类型都是大端,float 都是iee那个标准,也可以这种传输。
当然有更好的解决办法,用protobuf,protobuf数据里面就做了这种事情。
另外本地数据如果用memcpy存储到本地,不做这种处理的话,也会出现当前问题。