本人一直有個疑惑,大小端通信怎么存儲(以前一直知道這個概念,但怎么都跟實際匹配不上,網絡上也並沒有說怎么處理大小端通信問題)
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存儲到本地,不做這種處理的話,也會出現當前問題。