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