C++通过Sokcet发送结构体到Java
1. C++中结构体的定义
class QingParams
{
public:
QingParams()
{
width = 1024;
height = 768;
filelength = width * height*3;
char *filename= "default.image";
namelength = strlen(filename);
strcpy(name,filename);
total = (namelength + 24);
}
QingParams(int length,char * filename)
{
width = 1024;
height = 768;
filelength = length;
namelength = strlen(filename);
strcpy(name,filename);
total = (namelength + 24);
}
~QingParams()
{
//delete[] name;
cout<<"desconstructed called.";
}
void SetWidth(int w)
{
width = w;
}
void SetHeight(int h)
{
height = h;
}
int GetStructSize()
{
return total;
}
void print()
{
cout<<"total is "<<total<<endl;
cout<<"filelength is "<<filelength<<endl;
cout<<"width is "<<width<<endl;
cout<<"height is "<<height<<endl;
cout<<"name is "<<name<<endl;
cout<<"namelength is "<<namelength<<endl;
}
void converToInternetType()
{
total = htonl(total);
filelength = htonl(filelength);
namelength = htonl(namelength);
width = htonl(width);
height = htonl(height);
}
void converToHostType()
{
total = ntohl(total);
filelength = ntohl(filelength);
namelength = ntohl(namelength);
width = ntohl(width);
height = ntohl(height);
}
private:
int total;
int filelength;
int width;
int height;
int namelength;
char name[255];
};
1.1 结构体解析
Sizeof(int) = 4;
Sizeof(char) = 1;
Sizeof(char*) = 4;
整个结构体的大小为286.因为要4个字节对齐,4*5+(255/4)*4 = 286.
当类中char name[0]时,结构体的大小为 4*5+0 = 20.
1.2 结构体中不用指针,采用定长数组
当charname[255],定义为char * name,然后在初始化的时候,指针指向的是本地内存空间的一个地址,当这个地址被发送到java端的时候,这个指针指向的地方肯定是不对的。所以要用定长的数组来保存文件名字。
2. Socket中的字节流
2.1 C++
QingParams p(123,"三维重建.bmp");
int len = htonl(p.GetStructSize());
len = send(sockClient,(char*)&len,sizeof(p.GetStructSize()),0);
cout<<"send len is "<<len<<endl;
p.print();
len = p.GetStructSize();
p.converToInternetType();
len = send(sockClient,(char*)&p,len,0);
cout<<"send len is "<<len<<endl;
cout<<"sendover..."<<endl;
1) 在发送的时候,直接将QingParams结构体转为char *发送。
2) 由于在C++端的字节编码是小端字节,所以发送要将所有的多字节的类型全部转为大端字节类型,p.converToInternetType(),然后再发送。
2.2 Java端
Java端首先收到一个int的4个byte,然后解析这个int为36,接下去再读取36个byte,打印成二进制,输出结果如下:
00000000
00000000
00000000
00100100
00000000
00000000
00000000
01111011
00000000
00000000
00000100
00000000
00000000
00000000
00000011
00000000
00000000
00000000
00000000
00001100
11001000
11111101
11001110
10101100
11010110
11011000
10111101
10101000
00101110
01100010
01101101
01110000
00000000
11001100
11001100
11001100
3. java端解析
这里的字节顺序和在C++中定义的顺序严格定义。
private:
int total;
int filelength;
int width;
int height;
int namelength;
char name[255];
所以解析的时候为:
total: = 36
00000000
00000000
00000000
00100100
filelength: = 123
00000000
00000000
00000000
01111011
width: = 1024
00000000
00000000
00000100
00000000
height: = 768
00000000
00000000
00000011
00000000
namelength: = 12
00000000
00000000
00000000
00001100
char name[255]:
11001000 --------> ASCII码为:200
11111101 --------> ASCII码为:253
11001110 --------> ASCII码为:206
10101100 --------> ASCII码为:172
11010110 --------> ASCII码为:214
11011000 --------> ASCII码为:216
10111101 --------> ASCII码为:189
10101000 --------> ASCII码为:168
00101110 --------> ASCII码为:46 ----> .
01100010 --------> ASCII码为:98 ----> b
01101101 --------> ASCII码为:109 ----> m
01110000 --------> ASCII码为:112 ----> p
00000000 --------> ASCII码为:0 ----> ‘\0’
11001100 --------> ASCII码为:204
11001100 --------> ASCII码为:204
11001100 --------> ASCII码为:204
在charname[255]中,最后三行打了删除符号的意思,就是我只取前面的12个byte作为我的name的数据,第13个byte是C++中的\0,这个在java就不需要了,就不要在多读取一个字节了。