java与 C++ 之间进行 SOCKET 通讯要点简要解析
big-endian也稱高位在前、大端在前。是?計算機體系結構中一種描述多字節存儲順序的術語,在這種機制中最重要字節(MSB?)存放在最低端的地址?上。采用這種機制的處理器有Mortolora??PowerPC?微處理器系列和絕大多數的?RISC?處理器。
big-endian?最直觀的字節序:
內存地址從左到右與值由低到高的順序相對應。
little-endian也稱低位在前、小端在前。?計算機體系結構中一種描述多字節存儲順序的術語,在這種機?制中最不重要字節(LSB?)存放在最低端的地?址上。采用這種機制的處理器有?Intel?x86?系列微處理器和一些網絡通信設備。該術語除了描述多字節存儲順序外還常常用來描述一個字節中各個比特的排放次序?,這里僅討論多字節存儲循序?。
little-endian是最符合人的思維的字節序,低與低,高與高一一對應:
地址低位存儲值的低位?
地址高位存儲值的高位
??
?????下面舉一個例子具體說明?big-endian?與?little-endian:
??????int??nValue?=?0×01020304;
??????上面的整型nValue?有?4?個字節,其中?01?為最高位的字節,?04?為最低位的字節。那么在內存(或文件)中,該值的存儲循序為:
??????內存(或文件)地址:0×12000001??0×12000002??0×12000003??0×12000004??
??????Big-endian?????????:??????01?????????02???????????03?????????04
??????Little-endian????????:??????04?????????03???????????02?????????01
????
??????如果用一個byte?數組來保存的話,也就是如下:
??????Big-endian模式下:??byte??byValue[]?=?{0×01,?0×02,?0×03,?0×04};
??????Little-endian模式下:?byte??byValue[]?=?{0×04,?0×03,?0×02,?0×01};
Big-endian?或是?little-endian的判斷:
bool???IsLittleEndian?()
{
?????? int?????i???????=?1;??
?????? char??*?p???????=?(?char?*)&?i?;??
?? i?f????(???*?p????=???1???)????????????
????????? return???true?;????//?小端?
?? else
??return???false?;???//?大端
}
在各種計算機體系結構中,對于字節、字等的存儲機制有所不同,因而引發了計算機通信領域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節、字、雙字等等)應該以什么樣的順序進行傳送。如果不達成一致的規則,?通信雙方?將無法進行正確的編/?譯碼從而導致通信失敗。
通常所說的網絡字節序(Network?Byte?Order?)就是遵循?big-endian?規則。實際通信過程中,通信雙方需要把數據按照?big-endian?編碼再通過網絡傳輸。
通常所說的主機字節序(Host?Byte?Order?),與?CPU?的字節序一致。?x86?系列主機的字節序都是?little-endian?桂冊。所有?little-endian?規則主機直接通過網絡通訊的時候,需要進行字節序轉化。
????為了進行轉換?bsd?socket?提供了轉換的函數?有下面四個
?htons?把?unsigned?short?類型從主機?字節?序轉換到?網絡字節序
?htonl?把?unsigned?long?類型從主機?字節?序轉換到?網絡字節序
?ntohs?把?unsigned?short?類型從?網絡字節序?轉換到主機?字節?序
?????ntohl?把?unsigned?long?類型從網絡?字節?序轉換到主機?字節?序
????在使用little?endian?的系統中這些函數會把字節序進行轉換
????在使用big?endian?類型的系統中這些函數會定義成空宏
由于Java?運行需要自己的虛擬機來支持,所以?Java?程序所支持的字節序與?Java?虛擬機一致。Java?虛擬機遵循的是?big-endian?規則。所以可以把?Java?字節序看作是遵循?big-endian?規則的主機字節序。
4.1?字節序問題
一直以來都在進行著C++?上面的網絡開發,發現在?C++?上面進行通訊的時候,基本上都沒有考慮到網絡字節序的問題,特別是網絡應用中的用戶數據。大家都知道網絡通訊傳輸的都是字節流的數據,于是都是定義一個?char?類型的緩沖區,然后不管?int?,?WORD,?DWORD?還是其他自定義類型的結構對象也好,都直接?memcpy()?拷貝到緩沖區,直接發送出去了,根本都沒有考慮所傳輸數據的網絡字節序問題。如果非要說一點關注了網絡字節序問題的話,那就是有一個地方,大家都回去用到的,也就是網絡通訊端口,把端口號賦值給?sockaddr_in?.sin_port之時大家都會使用了htons()?,也就是把端口號從主機字節序轉化為網絡字節序。
因為這些程序的服務器端也好,客戶端也好,都是在x86?系列系統下運行,并且都是?C++?編譯出來的,所以不會因為字節序而出現問題。
現在所做項目,涉及到Java?與?C++?之間的?SOCKET?通訊,這樣的情況下,就需要大家都按規則來辦事了,?C++?方面傳輸的多字節類型數據還請從主機字節序轉化成網絡字節序再進行傳輸。
當然,數據是由程序員來組合的,也是由程序員來解析的,所以如果不按標準行事也是可以的。但是就需要在解析數據的時候注意好了。
建議還是按標準行事,把數據轉化成網絡字節序。
?????PS:
?????Java與?Windows?平臺下其他開發語言之間進行數據交與,也需要遵循該原則;
?????Java下讀寫?Windows?平臺下其他開發語言保存的數據,或是?Windows?平臺下其他語言讀寫Java?保存的數據,也需要注意字節序問題。
4.2?字節對齊問題
#include???<iostream>
using???namespace???std?;
typedef???struct???tag_S1
{
?????char???s_szValue?[8];
?????char???s_cValue?;
}??S1?;
typedef???struct???tag_S2
{
?????int????s_nValue1?;
?????char???s_szValue?[8];
?????char???s_cValue?;
?????int????s_nValue2?;
}??S2?;
typedef???struct???tag_S3
{
?????int????s_nValue?;
?????char???s_cValue?;
}??S3?;
#pragma???pack?(?push?,?1)
typedef???struct???tag_S4
{
?????int????s_nValue?;
?????char???s_cValue?;
}??S4?;
#pragma???pack?(?pop?)
int???main?(?int???argc?,??char?*??argv?[])
{???
?????cout??<<??“sizeof(S1):”??<<??sizeof?(?S1?)?<<??endl?;
?????cout??<<??“sizeof(S2):”??<<??sizeof?(?S2?)?<<??endl?;
?????cout??<<??“sizeof(S3):”??<<??sizeof?(?S3?)?<<??endl?;
?????cout??<<??“sizeof(S4):”??<<??sizeof?(?S4?)?<<??endl?;
?????system?(?“pause”?);
?????return??0;
}
上面的程序在?WinXP?sp3?+?VS2008Sp1下運行結果如下:
sizeof(S1):9
sizeof(S2):20
sizeof(S3):8
sizeof(S4):5
請按任意鍵繼續.?.?.
Win32位平臺下的微軟?C?編譯器?(cl.exe?for?80×86)?的對齊策略:
1)?結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;
備注:編譯器在給結構體開辟空間時,首先找到結構體中最寬的基本數據類型,然后尋找內存地址能被該基本數據類型所整除的位置,作為結構體的首地址。將這個最寬的基本數據類型的大小作為上面介紹的對齊模數。
2)?結構體每個成員相對于結構體首地址的偏移量(?offset?)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(?internal?adding?);
備注:?為結構體的一個成員開辟空間之前,編譯器首先檢查預開辟空間的首地址相對于結構體首地址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上一個成員之間填充一定的字節,以達到整數倍的要求,也就是將預開辟空間的首地址后移幾個字節。
3)?結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要,編譯器會在最末一個成員之后加上填充字節(?trailing?padding?)。
備注:結構體總大小是包括填充字節,最后一個成員滿足上面兩條以外,還必須滿足第三條,否則就必須在最后填充幾個字節以達到本條要求。???
????Windows?32位系統下,?VC?中,默認的字節對齊方式是?4?字節對齊。
sizeof(S1)?:因為結構中數據類型都是?char?,最寬基本類型大小是?1?,所以結構大小為?9,?S1?沒有進行填充;
sizeof(S2)、?sizeof(S3)?:?S2?,?S3?就被填充了一定的字節;
sizeof(S4):因為設置了對齊方式為?1?字節對齊,所以不會被填充。
在Java?與?C++?進行?SOCKET?通訊的?C++?端程序,建議涉及網絡通訊的結構使用?1?字節對齊方式,不然?Java?端會增加數據處理的復雜度。
4.3?Java與?C++?之間基本數據類型的差別
需要注意以下幾個數據類型的區別(32?位系統下?)?:
??????C++???????????????????????Java
??char———1byte????????? Byte———-1byte
??????????????????????????????Char———-2byte2
??long———4bytes???????? long———-8bytes
注意:
Java中的?Char?是一個字符,而不是一個字節,與?VC?的?WORD?長度一致;
Java中的?Byte?是一個字節,與?C++?中的?char?含義一致,而?VC?中的?BYTE?是無符號的char?;
Java中的?long?長度為?8?,而?VC?中的?long?長度為?4?(?C++?中?short?,?long?的長度跟編譯器的實現相關)。
No tags for this post. 除非注明,本站文章均為原創或編譯,轉載請注明: 文章來自KENGINE | Kankanews.com總結
以上是生活随笔為你收集整理的java与 C++ 之间进行 SOCKET 通讯要点简要解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++后台服务程序开发模式
- 下一篇: s3c2440移植MQTT