在C中使用大量字符的字节顺序
嘿伙计们,来自C / Networking新手的问题……
我在C中进行一些套接字编程,并试图解决字节顺序问题。 我的请求(发送)很好,但是当我收到数据时,我的字节都乱了。 我从这样的事情开始……
char * aResponse= (char *)malloc(512); int total = recv(sock, aResponse, 511, 0);
在处理这个响应时,每个16位字似乎都反转了它(我正在使用UDP)。 我试图通过做这样的事来解决这个问题……
unsigned short * _netOrder= (unsigned short *)aResponse; unsigned short * newhostOrder= (unsigned short *)malloc(total); for (i = 0; i < total; ++i) { newhostOrder[i] = ntohs(_netOrder[i]); }
当我将数据视为一个short时,这可以正常工作,但是如果我再次将指针转换为char,则字节会反转。 我究竟做错了什么?
谢谢!
好吧,你在两个不同的层面上做的事情似乎有问题。 这里混淆的一部分似乎源于你使用指针,它们指向什么类型的对象,然后解释指针所指向的内存中值的编码。
内存中多字节实体的编码被称为endianess。 这两种常见编码称为Little Endian (LE)和Big Endian (BE)。 对于LE,像short这样的16位数量首先是编码最低有效字节(LSB)。 在BE下,首先编码最高有效字节(MSB)。
按照惯例,网络协议通常将事物编码为我们称之为“网络字节顺序”(NBO)的东西,它也恰好与BE相同。 如果您要在大端平台上发送和接收内存缓冲区,那么您将不会遇到转换问题。 但是,您的代码将依赖于BE约定的平台。 如果要编写可在LE和BE平台上正常运行的可移植代码,则不应假设平台的字节顺序。
实现字节序可移植性是ntohs() , ntohl() , htons()和htonl()等例程的目的。 这些函数/宏在给定平台上定义,以在发送和接收端进行必要的转换:
- htons() – 将短值从主机订单转换为网络订单(用于发送)
- htonl() – 将长值从主机顺序转换为网络顺序(用于发送)
- ntohs() – 将网络订单的短值转换为主机订单(收到后)
- ntohl() – 将长值从网络顺序转换为主机顺序(接收后)
了解在回送到字符时有关访问内存的注释不会影响内存中实体的实际顺序。 也就是说,如果您以一系列字节的forms访问缓冲区,无论您有BE还是LE机器,您都会看到它们实际编码到内存中的字节数。 因此,如果您在接收后查看NBO编码的缓冲区,MSB将始终是第一个。 如果在转换回主机顺序后查看输出缓冲区,如果您有BE机器,则字节顺序将保持不变。 相反,在LE机器上,现在所有字节都将在转换后的缓冲区中反转。
最后,在转换循环中,变量total
指的是字节。 但是,您正在访问缓冲区作为shorts
。 你的循环守卫不应该是total
,但应该是:
total / sizeof( unsigned short )
考虑每个short
双字节性质。
当我将数据视为一个short时,这可以正常工作,但是如果我再次将指针转换为char,则字节会反转。
这就是我所期待的。
我究竟做错了什么?
你必须知道发送者发送了什么:知道数据是字节(不需要反转),还是短路或长信(确实如此)。
Google提供与ntohs
, htons
和htons
API相关的教程。
目前还不清楚aResponse
代表什么(字符串?struct?)。 字节序仅与数值有关,而不是char
。 您还需要确保在发送方,所有数值都从主机转换为网络字节顺序( hton*
)。
除了你原来的问题(我认为已经回答了),你应该看一下你的malloc语句。 malloc分配字节,无符号短路最可能是两个字节。
您的陈述应如下所示:
unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short));
网络字节顺序是大端,所以你需要将它转换为小端,如果你想要它有意义,但如果它只是一个数组它不应该大惊小怪,发送者如何发送它的数据?
对于单字节,我们可能不关心字节排序。