这周公司分配任务让写一个UDP服务器端用于单向接收数据包;本来程序不是很复杂,但还是由于字节序的问题在调试的过程中浪费了大量的时间
主要原因是客户端是采用java代码编写的,而我一直对java又不是很熟悉,现在做个总结
1.java 与 C 的数据类型
java 与 c 的数据类型基本上是能一一对上的,主要区别是java 的long 型是8字节,而C 语言在32位机上long型为4字节,在64位机上是8字节
为了安全起见,在数据接收的时候最好用long long型,这样就能保证代码能跑在不同平台上
2.字节序问题
做过网络编程的都知道字节序的问题,主要是由于CPU平台的不同造成的,我觉得因该是个历史遗留问题吧。
在写这个程序的时候,对端和我都是在x86 pc上跑的,而且在封装udp包的时候是拆分成字节的形式发送的,到了对端重新组装,所以我觉得不用多考虑字节序的问题
但是问题就出在这了,对端发送的数据包里long型的数据到我这边之后值不是我应该得到的值,我第一个反应是字节序的问题,然后使用htonl简单尝试之后发现不对就去尝试别的方法了,最后通过抓包发现传过来的数据就是字节序到装了,这是什么原因呢,我已经尝试过字节序转换为什么不行呢,通过反复查阅资料,终于找出了原因
最主要的原因:jave 只有大端存储
由于对字节序和 java 语言不是很熟悉,我一直以为字节序是CPU平台不同造成的,其实不同语言之间也存在字节序的问题,与C 语言不同,java 语言在任何平台下都是大端存储的,所以在这样跨语言交叉通讯的时候要格外小心。
第二个原因:
数据结果不对,我第一时间就想到了可能是字节序的问题,可是还是在使用htol之后结果还是不对的,这是为什么,我们看一下网络字节序转换的几个函数:
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
仔细看这几个函数并不支持 8 字节数据的字节序转换,如果用htonl 转换 8位的long型的话,高位就会丢失,变成全零,最后我解决这个问题的办法是自己写了一个函数去手动转换
好了,明白了这两点,在编写这类程序的时候就没多大问题了。
最后一点有趣的是,我发现虽然这组函数分了 htonl 和 ntohl,但对一个待转换的数而言,这两个函数随便哪一个都是转换了字节序
即: 使用两次同一个函数和分别使用一次两个函数,结果都是一样的:
int a = 48; / /a--> 0x30 0x00 0x00 0x00
int b = htonl(a) // b--> 0x00 0x00 0x00 0x30
int c = ntohl(a) // c--> 0x00 0x00 0x00 0x30
int d = ntohl(c) // d--> 0x30 0x00 0x00 0x00
为什么要将同样功能的函数分为两个实现,哪位大神来告诉我下
e-mail : mhpmii@126.com