最近在做一个项目,就是设计一套通信协议,利用nginx来实现解析。协议内容是包括整数和字符串,现在客户端收到服务器端发送的网络字节流时,需要从中提取出整数,再根据整数决定发送数据量的大小。如下所示:
p = u->buffer.pos;
num=*(int*)p
p指向接收到的网络字节流,用这么方式解析得到的整形num不是服务器端发送的数字,是一个很大的数。不对,于是换了种方式:
memcpy(num,p,sizeof(int));
printf("num is %d
",*(int*)num);
结果还是一样。
但是输出字节流p,能看到后面的字符串是能得到的,但是前面的整数得不到
for(i=0;i<9;i++){
printf("i :%c
",p[i]);
}
于是改成以16进制形式输出,结果是可以查看到整数值:
pos last 0
pos last 0
pos last 0
pos last 5
pos last 77
pos last 67
pos last 70
pos last 31
pos last 66
即第4字节的那个5正式服务器端发送的数字,这说明网络字节流是对的。只是不能那样取出来。
这个时候就必须熟悉网络字节流的概念了,搜了下:
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
主机字节序就是我们平常说的大端和小端模式:不同的 CPU 有不同的字节序类型,这些字节序是指整数在内存中保存的顺序 这个叫做主机序。
就是网络字节流的序列和主机的序列可能不一样,所以需要一些函数进行转换,linux提供了四个函数:
为了进行转换 bsd socket提供了转换的函数 有下面四个
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
把代码改成:
p=u->buffer.pos;
htnum=ntohl(*(int*)p);
printf("htmum=%d,%x
",htnum,htnum);
搞定得到正确结果。
这说明进行网络编程时得注意网络字节流的序列,否则不能提取出对应的数据。