java 和C++ Socket程式傳送結構體
主要技術問題:windows,linux等系統採用LITTLE_ENDIAN位元組序,而java自身採用BIG_ENGIAN位元組序,BIG_ENGIAN是指低地址存放最高有效位元組(MSB),而LITTLE_ENDIAN則是低地址存放最低有效位元組。Java程式寫的客戶程式端同c++的服務端程式互動時結構體的某些資料型別需要轉換位元組序。本文解決方法,java客戶端程式傳送資料時做相應的轉換位元組序,等收到資料時再做一次位元組序的轉換。
現在的網路程式多數採用可靠交付的TCP協議,其採用位元組流的傳輸方式,c++程式中用結構體來模擬報頭以此界定每次傳送的報文。所以網路中整個位元組流的格式:報頭+資料負載+報頭+資料負載……
本文基於c++寫服務端和java寫客戶端應用場景描述。服務端程式收到客戶端傳送的報文後將原報文做一個回射。
採用報頭:
Struct Header{
Intcmd; //標示報文用途
Intlength; //資料負載長度
Intpara1; //服務端處理完結果
Int para2; //服務端處理完結果
Int para3; //服務端處理完結果
}; 此時套介面的讀寫方式為先讀報頭,在報頭中取出資料負載的長度,然後再讀相應位元組的資料。
Java客戶端程式碼:
報頭類:
publicclassMsgHeader {
privateintcmd;
privateintlength;
privateintpara1;
privateintpara2;
publicint getCmd() {
returncmd;
}
publicvoid setCmd(int cmd) {
this.cmd = cmd;
}
publicint getLength() {
returnlength;
}
publicvoid setLength(int length) {
this.length = length;
}
publicint getPara1() {
returnpara1;
}
publicvoid setPara1(int para1) {
this.para1 = para1;
}
publicint getPara2() {
returnpara2;
}
publicvoid setPara2(int para2) {
this.para2 = para2;
}
publicint getPara3() {
returnpara3;
}
publicvoid setPara3(int para3) {
this.para3 = para3;
}
privateintpara3;
public MsgHeader()
{
this.cmd = 0;
this.length = 0;
this.para1 = 0;
this.para2 = 0;
this.para3 = 0;
}
public MsgHeader(int cmd,int length,int para1,int para2,int para3){
this.cmd=cmd;
this.length= length;
this.para1 = para1;
this.para2 = para2;
this.para3 = para3;
}
}
公共操作類:
publicclassCommon {
//位元組序轉換
publicstaticbyte[] toLH(int n) {
byte[] b =newbyte[4];
b[0]= (byte)(n & 0xff);
b[1]= (byte)(n >> 8 & 0xff);
b[2]= (byte)(n >> 16 & 0xff);
b[3]= (byte)(n >> 24 & 0xff);
return b;
}
//btye陣列轉換為int型
publicstaticint bytes2Integer(byte[] byteVal) {
int result = 0;
for (int i = 0; i < byteVal.length; i++) {
int tmpVal = (byteVal[i]<< (8 * (3 - i)));
switch (i) {
case 0:
tmpVal= tmpVal & 0xFF000000;
break;
case 1:
tmpVal= tmpVal & 0x00FF0000;
break;
case 2:
tmpVal= tmpVal & 0x0000FF00;
break;
case 3:
tmpVal= tmpVal & 0x000000FF;
break;
}
result= result | tmpVal;
}
return result;
}
}
協議類:
publicclassProtocol {
publicstaticfinalintPORTAL_DBC_INSTALLSYSTEM= 0x05000030;
publicstaticfinalintPORTAL_DBC_INSTALLSYSTEM_ACK= 0x05000031;
/*
* add all protocol
*
*
*
*/
}
資料收發類:
publicclassDBCAgent {
private Socketsocket = null;
privatebyte[]buffer;
public DBCAgent() {
try {
this.socket =new Socket("192.168.9.64",8886);
}catch(UnknownHostException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
//收資料
publicvoid recvData()throws IOException {
byte[] recvHead =newbyte[4];
int cForm;
intcmd, length, para1,para2, para3;
// readcmd轉換位元組序
socket.getInputStream().read(recvHead,0, 4);
cForm= Common.bytes2Integer(recvHead);
cmd= Common.bytes2Integer(Common.toLH(cForm));
// read length轉換位元組序
socket.getInputStream().read(recvHead,0, 4);
cForm= Common.bytes2Integer(recvHead);
length= Common.bytes2Integer(Common.toLH(cForm));
// read para1轉換位元組序
socket.getInputStream().read(recvHead,0, 4);
cForm= Common.bytes2Integer(recvHead);
para1= Common.bytes2Integer(Common.toLH(cForm));
// read para2轉換位元組序
socket.getInputStream().read(recvHead,0, 4);
cForm= Common.bytes2Integer(recvHead);
para2= Common.bytes2Integer(Common.toLH(cForm));
// read para3轉換位元組序
socket.getInputStream().read(recvHead,0, 4);
cForm= Common.bytes2Integer(recvHead);
para3= Common.bytes2Integer(Common.toLH(cForm));
byte[] recvData =newbyte[length];
// read data
socket.getInputStream().read(recvData,0, length);
StringDataStr = newString(recvData);
System.out.println(DataStr);
}
發資料類:
publicboolean sendData(String data) {
byte[] temp =null;
MsgHeaderheader = newMsgHeader();
header.setLength(data.length());
this.buffer =newbyte[data.length() + 20];
// addcmd 轉換位元組序
temp= Common.toLH(Protocol.PORTAL_DBC_INSTALLSYSTEM);
System.arraycopy(temp,0,buffer,0, 4);
// addlength轉換位元組序
temp= Common.toLH(header.getLength());
System.arraycopy(temp,0,buffer,4, 4);
// add para1轉換位元組序
temp= Common.toLH(header.getPara1());
System.arraycopy(temp,0,buffer,8, 4);
// add para2轉換位元組序
temp= Common.toLH(header.getPara2());
System.arraycopy(temp,0,buffer,12, 4);
// add para3轉換位元組序
temp= Common.toLH(header.getPara3());
System.arraycopy(temp,0,buffer,16, 4);
System.arraycopy(data.getBytes(),0,buffer,20, data.length());
try {
socket.getOutputStream().write(this.buffer);
}catch(IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
returntrue;
}
}
測試類:
publicclassTest {
/**
* @param args
* @throws IOException
*/
publicstaticvoid main(String[] args)throws IOException {
//TODO Auto-generated method stub
DBCAgentdbcAgent = newDBCAgent();
//傳送資料
dbcAgent.sendData("Helloaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
//接收資料
dbcAgent.recvData();
try {
Thread.sleep(10000);
}catch(InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}