Linux网络编程多字节数据的收发.docx
- 文档编号:25037214
- 上传时间:2023-06-04
- 格式:DOCX
- 页数:10
- 大小:16.46KB
Linux网络编程多字节数据的收发.docx
《Linux网络编程多字节数据的收发.docx》由会员分享,可在线阅读,更多相关《Linux网络编程多字节数据的收发.docx(10页珍藏版)》请在冰豆网上搜索。
Linux网络编程多字节数据的收发
Linux网络编程-多字节数据的收发
Linux网络编程-多字节数据的收发.txt珍惜生活——上帝还让你活着,就肯定有他的安排。
雷锋做了好事不留名,但是每一件事情都记到日记里面。
Linux网络编程一步一步学-多字节数据的收发
首先,必须说明的是网络上的数据是流式传送的,也就是经常说的stream,流式传送的特点就是一方发送的是1234四个字节,那么接收端收到的必然是1234四个字节,顺序完全相同。
其次,必须说明的是主机字节序,不同CPU保存数据的方式不同,即高位在前还是低位在前的问题的,大家可以自己google搜索一下“biglittleendianCPU”会发现很多人解释这个问题。
对于单个字节的数据,即存储空间占用1Byte的数据,没有任何问题,但由于数据很大,通常1Byte表示不了,就必须引入多字节表示的数据,比如一个int通常为32个bit的数据,即4Byte表示一个int,那么当你定义一个int型变量x时,它的值可能是0x1234,即x=0x1234;但如果是另外一种顺序,则x=0x4321,显然这两个数相差很大。
big-endian和little-endian问题简单说来就是对于同样的4个字节1234,一种顺序表示为1234,另一种顺序可能表示为4321。
这就象中文表示姓名和英文表示姓名的顺序不一样,中国人姓名表示时姓在前名在后,而英文习惯里表示姓名时名在前姓在后,对于汉语的zhoulifa,英文里可能写成lifazhou。
如果双方不知道这个差别,英文习惯的人听汉语的人说人名zhoulifa里必然以为是姓lifa的叫zhou的人。
你可以用这个程序来测试你的主机字节序:
#include
#include
intmain(void)
{
printf("big:
%dlittle:
%dmine:
%d\n",__BIG_ENDIAN,__LITTLE_ENDIAN,__BYTE_ORDER);
return0;
}
因此,基于上述两点我们就明白了“多字节数据传送必须要关注数据顺序”。
对于单字节的数据,比如char型的,没有问题,所以在前面所有例子程序中,一个程序发送“hello,Linux”,另一个程序必然同样收到这样的字符串而不会顺序乱了。
但如果你在这边发过去四个字节1234表示一个int数据,对方接收到以后不知道你的机器是big-endian还是little-endian,按照它自己的理解来解释这个数字,可能这个数字就是4321了。
好在前人已经想到这个问题了,因此网络编程基础“TCP/IP协议”里已经规定所有在网络上传送的数据统一采用big-endian顺序。
因此,正确的网络编程方法是这样的:
如果你要发送纯字符串给对方,那么相当容易,可以这样:
charbuf[]="Thisisateststring";
......
ret=send(socket_fd,buf,strlen(buf),0);
......
如果你要发送多字节数据,比如short,int,float,double,long……你必须先转换为big-endian序再发送,比如:
intage=30;
……
age=htonl(age);
ret=send(socket_fd,(void*)&age,sizeof(int),0);
……
这里涉及一些网络字节序和主机字节序转换的函数,把主机(host)字节序转换为网络(network)字节序用到htons,htonl等函数,反之则用ntohs,ntohl等函数。
man一下就知道这几个函数的用处和用法了。
对于结构数据的传送
比如有这样一个表示人员信息的结构:
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
当你定义了一个变量structmemberpersonalInfo并把personalInfo的各字段内容准备好了,如何把这个信息发送给对方呢?
一种方法:
发送和接收的双方都知道上述结构structmember的定义,因此,不管一个人的名字是几个字节,也不管这个人的住址信息是多少个字节,发送的一方可以这样写程序:
structmemberpersonalInfo;
......
ret=send(socket_fd,personalInfo.name,32,0);
......
personalInfo.age=htonl(personalInfo.age);
ret=send(socket_fd,(void*)&personalInfo.age,sizeof(int),0);
......
ret=send(socket_fd,&personalInfo.gender,sizeof(char),0);
......
ret=send(socket_fd,personalInfo.address,128,0);
......
而接收一方则可以这样写程序:
structmemberpersonalInfo;
......
ret=recv(socket_fd,personalInfo.name,32,0);
......
ret=recv(socket_fd,(void*)&personalInfo.age,sizeof(int),0);
personalInfo.age=ntohl(personalInfo.age);
......
ret=recv(socket_fd,&personalInfo.gender,sizeof(char),0);
......
ret=recv(socket_fd,personalInfo.address,128,0);
......
当然,这样写程序的前提仍然是双方是32位或64位系统,如果一方是32位系统,他这里表示的sizeof(int)是32bit个字节,而另一方表示的是64bit,程序工作会有问题的。
另一种方法:
发送方这样写程序:
#pragmapack
(1)/*这一行应在定义structmember时写*/
structmemberpersonalInfo;
......
personalInfo.age=htonl(personalInfo.age);
ret=send(socket_fd,(void*)&personalInfo,sizeof(structmember),0);
......
接收方这样写程序:
#pragmapack
(1)/*这一行应在定义structmember时写,不一定要写成1,关键是要与发送方的定义保持一致*/
structmemberpersonalInfo;
......
ret=recv(socket_fd,(void*)&personalInfo,sizeof(structmember),0);
personalInfo.age=ntohl(personalInfo.age);
......
这种方法要注意的是双方有个一致的定义pack
(1)即,按位对齐方式定义相同。
在网上搜索“Cpragmapack”会发现很多这样的讨论。
当然也可以试试这几段代码的结果:
#include
#pragmapack
(1)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack
(2)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(3)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(4)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(5)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(6)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(7)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
#include
#pragmapack(8)
intmain(void)
{
structmember{
charname[32];
intage;
chargender;
charaddress[128];
};
printf("sizeis:
%d\n",sizeof(structmember));
return0;
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 网络 编程 多字 数据 收发