java与 C++ 之间进行 SOCKET 通讯要点简要解析
big-endian也稱(chēng)高位在前、大端在前。是?計(jì)算機(jī)體系結(jié)構(gòu)中一種描述多字節(jié)存儲(chǔ)順序的術(shù)語(yǔ),在這種機(jī)制中最重要字節(jié)(MSB?)存放在最低端的地址?上。采用這種機(jī)制的處理器有Mortolora??PowerPC?微處理器系列和絕大多數(shù)的?RISC?處理器。
big-endian?最直觀的字節(jié)序:
內(nèi)存地址從左到右與值由低到高的順序相對(duì)應(yīng)。
little-endian也稱(chēng)低位在前、小端在前。?計(jì)算機(jī)體系結(jié)構(gòu)中一種描述多字節(jié)存儲(chǔ)順序的術(shù)語(yǔ),在這種機(jī)?制中最不重要字節(jié)(LSB?)存放在最低端的地?址上。采用這種機(jī)制的處理器有?Intel?x86?系列微處理器和一些網(wǎng)絡(luò)通信設(shè)備。該術(shù)語(yǔ)除了描述多字節(jié)存儲(chǔ)順序外還常常用來(lái)描述一個(gè)字節(jié)中各個(gè)比特的排放次序?,這里僅討論多字節(jié)存儲(chǔ)循序?。
little-endian是最符合人的思維的字節(jié)序,低與低,高與高一一對(duì)應(yīng):
地址低位存儲(chǔ)值的低位?
地址高位存儲(chǔ)值的高位
??
?????下面舉一個(gè)例子具體說(shuō)明?big-endian?與?little-endian:
??????int??nValue?=?0×01020304;
??????上面的整型nValue?有?4?個(gè)字節(jié),其中?01?為最高位的字節(jié),?04?為最低位的字節(jié)。那么在內(nèi)存(或文件)中,該值的存儲(chǔ)循序?yàn)?#xff1a;
??????內(nèi)存(或文件)地址:0×12000001??0×12000002??0×12000003??0×12000004??
??????Big-endian?????????:??????01?????????02???????????03?????????04
??????Little-endian????????:??????04?????????03???????????02?????????01
????
??????如果用一個(gè)byte?數(shù)組來(lái)保存的話,也就是如下:
??????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?;???//?大端
}
在各種計(jì)算機(jī)體系結(jié)構(gòu)中,對(duì)于字節(jié)、字等的存儲(chǔ)機(jī)制有所不同,因而引發(fā)了計(jì)算機(jī)通信領(lǐng)域中一個(gè)很重要的問(wèn)題,即通信雙方交流的信息單元(比特、字節(jié)、字、雙字等等)應(yīng)該以什么樣的順序進(jìn)行傳送。如果不達(dá)成一致的規(guī)則,?通信雙方?將無(wú)法進(jìn)行正確的編/?譯碼從而導(dǎo)致通信失敗。
通常所說(shuō)的網(wǎng)絡(luò)字節(jié)序(Network?Byte?Order?)就是遵循?big-endian?規(guī)則。實(shí)際通信過(guò)程中,通信雙方需要把數(shù)據(jù)按照?big-endian?編碼再通過(guò)網(wǎng)絡(luò)傳輸。
通常所說(shuō)的主機(jī)字節(jié)序(Host?Byte?Order?),與?CPU?的字節(jié)序一致。?x86?系列主機(jī)的字節(jié)序都是?little-endian?桂冊(cè)。所有?little-endian?規(guī)則主機(jī)直接通過(guò)網(wǎng)絡(luò)通訊的時(shí)候,需要進(jìn)行字節(jié)序轉(zhuǎn)化。
????為了進(jìn)行轉(zhuǎn)換?bsd?socket?提供了轉(zhuǎn)換的函數(shù)?有下面四個(gè)
?htons?把?unsigned?short?類(lèi)型從主機(jī)?字節(jié)?序轉(zhuǎn)換到?網(wǎng)絡(luò)字節(jié)序
?htonl?把?unsigned?long?類(lèi)型從主機(jī)?字節(jié)?序轉(zhuǎn)換到?網(wǎng)絡(luò)字節(jié)序
?ntohs?把?unsigned?short?類(lèi)型從?網(wǎng)絡(luò)字節(jié)序?轉(zhuǎn)換到主機(jī)?字節(jié)?序
?????ntohl?把?unsigned?long?類(lèi)型從網(wǎng)絡(luò)?字節(jié)?序轉(zhuǎn)換到主機(jī)?字節(jié)?序
????在使用little?endian?的系統(tǒng)中這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換
????在使用big?endian?類(lèi)型的系統(tǒng)中這些函數(shù)會(huì)定義成空宏
由于Java?運(yùn)行需要自己的虛擬機(jī)來(lái)支持,所以?Java?程序所支持的字節(jié)序與?Java?虛擬機(jī)一致。Java?虛擬機(jī)遵循的是?big-endian?規(guī)則。所以可以把?Java?字節(jié)序看作是遵循?big-endian?規(guī)則的主機(jī)字節(jié)序。
4.1?字節(jié)序問(wèn)題
一直以來(lái)都在進(jìn)行著C++?上面的網(wǎng)絡(luò)開(kāi)發(fā),發(fā)現(xiàn)在?C++?上面進(jìn)行通訊的時(shí)候,基本上都沒(méi)有考慮到網(wǎng)絡(luò)字節(jié)序的問(wèn)題,特別是網(wǎng)絡(luò)應(yīng)用中的用戶(hù)數(shù)據(jù)。大家都知道網(wǎng)絡(luò)通訊傳輸?shù)亩际亲止?jié)流的數(shù)據(jù),于是都是定義一個(gè)?char?類(lèi)型的緩沖區(qū),然后不管?int?,?WORD,?DWORD?還是其他自定義類(lèi)型的結(jié)構(gòu)對(duì)象也好,都直接?memcpy()?拷貝到緩沖區(qū),直接發(fā)送出去了,根本都沒(méi)有考慮所傳輸數(shù)據(jù)的網(wǎng)絡(luò)字節(jié)序問(wèn)題。如果非要說(shuō)一點(diǎn)關(guān)注了網(wǎng)絡(luò)字節(jié)序問(wèn)題的話,那就是有一個(gè)地方,大家都回去用到的,也就是網(wǎng)絡(luò)通訊端口,把端口號(hào)賦值給?sockaddr_in?.sin_port之時(shí)大家都會(huì)使用了htons()?,也就是把端口號(hào)從主機(jī)字節(jié)序轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序。
因?yàn)檫@些程序的服務(wù)器端也好,客戶(hù)端也好,都是在x86?系列系統(tǒng)下運(yùn)行,并且都是?C++?編譯出來(lái)的,所以不會(huì)因?yàn)樽止?jié)序而出現(xiàn)問(wèn)題。
現(xiàn)在所做項(xiàng)目,涉及到Java?與?C++?之間的?SOCKET?通訊,這樣的情況下,就需要大家都按規(guī)則來(lái)辦事了,?C++?方面?zhèn)鬏數(shù)亩嘧止?jié)類(lèi)型數(shù)據(jù)還請(qǐng)從主機(jī)字節(jié)序轉(zhuǎn)化成網(wǎng)絡(luò)字節(jié)序再進(jìn)行傳輸。
當(dāng)然,數(shù)據(jù)是由程序員來(lái)組合的,也是由程序員來(lái)解析的,所以如果不按標(biāo)準(zhǔn)行事也是可以的。但是就需要在解析數(shù)據(jù)的時(shí)候注意好了。
建議還是按標(biāo)準(zhǔn)行事,把數(shù)據(jù)轉(zhuǎn)化成網(wǎng)絡(luò)字節(jié)序。
?????PS:
?????Java與?Windows?平臺(tái)下其他開(kāi)發(fā)語(yǔ)言之間進(jìn)行數(shù)據(jù)交與,也需要遵循該原則;
?????Java下讀寫(xiě)?Windows?平臺(tái)下其他開(kāi)發(fā)語(yǔ)言保存的數(shù)據(jù),或是?Windows?平臺(tái)下其他語(yǔ)言讀寫(xiě)Java?保存的數(shù)據(jù),也需要注意字節(jié)序問(wèn)題。
4.2?字節(jié)對(duì)齊問(wèn)題
#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下運(yùn)行結(jié)果如下:
sizeof(S1):9
sizeof(S2):20
sizeof(S3):8
sizeof(S4):5
請(qǐng)按任意鍵繼續(xù).?.?.
Win32位平臺(tái)下的微軟?C?編譯器?(cl.exe?for?80×86)?的對(duì)齊策略:
1)?結(jié)構(gòu)體變量的首地址能夠被其最寬基本類(lèi)型成員的大小所整除;
備注:編譯器在給結(jié)構(gòu)體開(kāi)辟空間時(shí),首先找到結(jié)構(gòu)體中最寬的基本數(shù)據(jù)類(lèi)型,然后尋找內(nèi)存地址能被該基本數(shù)據(jù)類(lèi)型所整除的位置,作為結(jié)構(gòu)體的首地址。將這個(gè)最寬的基本數(shù)據(jù)類(lèi)型的大小作為上面介紹的對(duì)齊模數(shù)。
2)?結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(?offset?)都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上填充字節(jié)(?internal?adding?);
備注:?為結(jié)構(gòu)體的一個(gè)成員開(kāi)辟空間之前,編譯器首先檢查預(yù)開(kāi)辟空間的首地址相對(duì)于結(jié)構(gòu)體首地址的偏移是否是本成員的整數(shù)倍,若是,則存放本成員,反之,則在本成員和上一個(gè)成員之間填充一定的字節(jié),以達(dá)到整數(shù)倍的要求,也就是將預(yù)開(kāi)辟空間的首地址后移幾個(gè)字節(jié)。
3)?結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類(lèi)型成員大小的整數(shù)倍,如有需要,編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)(?trailing?padding?)。
備注:結(jié)構(gòu)體總大小是包括填充字節(jié),最后一個(gè)成員滿(mǎn)足上面兩條以外,還必須滿(mǎn)足第三條,否則就必須在最后填充幾個(gè)字節(jié)以達(dá)到本條要求。???
????Windows?32位系統(tǒng)下,?VC?中,默認(rèn)的字節(jié)對(duì)齊方式是?4?字節(jié)對(duì)齊。
sizeof(S1)?:因?yàn)榻Y(jié)構(gòu)中數(shù)據(jù)類(lèi)型都是?char?,最寬基本類(lèi)型大小是?1?,所以結(jié)構(gòu)大小為?9,?S1?沒(méi)有進(jìn)行填充;
sizeof(S2)、?sizeof(S3)?:?S2?,?S3?就被填充了一定的字節(jié);
sizeof(S4):因?yàn)樵O(shè)置了對(duì)齊方式為?1?字節(jié)對(duì)齊,所以不會(huì)被填充。
在Java?與?C++?進(jìn)行?SOCKET?通訊的?C++?端程序,建議涉及網(wǎng)絡(luò)通訊的結(jié)構(gòu)使用?1?字節(jié)對(duì)齊方式,不然?Java?端會(huì)增加數(shù)據(jù)處理的復(fù)雜度。
4.3?Java與?C++?之間基本數(shù)據(jù)類(lèi)型的差別
需要注意以下幾個(gè)數(shù)據(jù)類(lèi)型的區(qū)別(32?位系統(tǒng)下?)?:
??????C++???????????????????????Java
??char———1byte????????? Byte———-1byte
??????????????????????????????Char———-2byte2
??long———4bytes???????? long———-8bytes
注意:
Java中的?Char?是一個(gè)字符,而不是一個(gè)字節(jié),與?VC?的?WORD?長(zhǎng)度一致;
Java中的?Byte?是一個(gè)字節(jié),與?C++?中的?char?含義一致,而?VC?中的?BYTE?是無(wú)符號(hào)的char?;
Java中的?long?長(zhǎng)度為?8?,而?VC?中的?long?長(zhǎng)度為?4?(?C++?中?short?,?long?的長(zhǎng)度跟編譯器的實(shí)現(xiàn)相關(guān))。
No tags for this post. 除非注明,本站文章均為原創(chuàng)或編譯,轉(zhuǎn)載請(qǐng)注明: 文章來(lái)自KENGINE | Kankanews.com總結(jié)
以上是生活随笔為你收集整理的java与 C++ 之间进行 SOCKET 通讯要点简要解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++后台服务程序开发模式
- 下一篇: VC++中进程间相互通信的十一种方法