我正在阅读此example有关如何将NSData用于网络消息的信息。
创建NSData时,该示例使用:
unsigned int state = htonl(_state);
[data appendBytes:&state length:sizeof(state)];
当转换NSData时,该示例使用:
[data getBytes:buffer range:NSMakeRange(offset, sizeof(unsigned int))];
_state = ntohl((unsigned int)buffer);
在此示例中是否不必使用htonl和ntohl? - 由于数据在iOS设备上打包/解包,因此字节排序不一样,因此不必使用htonl和ntohl。 - 它的使用方式不正确吗?该示例使用htonl进行打包,使用ntohl进行解包。但实际上,如果有人知道发送者或接收者使用的是特定格式,那么不应该只这样做吗?
答案 0 :(得分:3)
该示例使用htonl进行打包,使用ntohl进行解包。
这是对的。
当发送方通过网络传输数据(整数,浮点数)时,它应将它们重新排序为“网络字节顺序”。接收器通过从网络字节顺序重新排序到“主机字节顺序”来执行解码。
但实际上,如果有人知道发件人或收件人使用的是特定格式,那么不应该只这样做吗?
通常,发送方不知道接收方的字节顺序,反之亦然。因此,为了避免歧义,需要定义“网络”的字节顺序。如果发送方和接收方实际上正确地对网络进行编码/解码,这种方法很有效。
如果您担心编码的性能:
在现代CPU上,字节交换所需的机器代码非常快。
在语言层面,编码和解码一系列字节的功能也可以非常快。但是,我们帖子中的Objective-C示例不属于那些“快速”例程。
例如,由于主机字节顺序在编译时是已知的,如果主机字节顺序等于网络字节顺序,ntohl
变为“空”功能(也称为“NoOp”)。
其他字节交换实用程序函数在ntoh
宏系列上扩展为64位,double和float值,可以使用C ++模板技巧,也可能成为“NoOp”函数。
然后可以完全进一步优化这些“空”函数,这有效地导致机器代码只执行从源缓冲区到目标缓冲区的move
。
但是,由于字节交换的额外开销非常小,因此在不需要交换的情况下,这些优化只能在高性能代码中被察觉。但是你的第一个声明:
[data getBytes:buffer range:NSMakeRange(offset, sizeof(unsigned int))];
比以下声明贵很多
_state = ntohl((unsigned int)buffer);
即使需要字节交换。