Ios 数据包解释

Ios 数据包解释,ios,ios6,nsdata,packet,Ios,Ios6,Nsdata,Packet,关于我正在制作的应用程序中数据包的解释,我有一个相当复杂的问题。主机应用程序向具有以下结构的客户端应用程序发送数据包: [10字节头][所选可变字节长客户端的删除][空字节][可变字节长客户端的删除][空字节][4字节的整数][可变字节长客户端的删除][空字节][4字节的整数] 以下是在此结构下生成的示例数据包: 434e4c50 00000000 006a3134 31303837 34393634 00313233 38313638 35383900 000003e8 31343130 38

关于我正在制作的应用程序中数据包的解释,我有一个相当复杂的问题。主机应用程序向具有以下结构的客户端应用程序发送数据包:

[10字节头][所选可变字节长客户端的删除][空字节][可变字节长客户端的删除][空字节][4字节的整数][可变字节长客户端的删除][空字节][4字节的整数]

以下是在此结构下生成的示例数据包:

434e4c50 00000000 006a3134 31303837 34393634 00313233 38313638 35383900 000003e8 31343130 38373439 363400000 0003e8

如下图所示:

CNLP j1410874964 1238168589Ë1410874964Ë

“CNLP j”是10字节的数据包头。“1410874964”是所选客户端的peerID。“1238168589”是另一个客户端的peerID。“Ë”的整数值为1000。“1410874964”是另一个客户端(在本例中为所选客户端)的peerID。“Ë”的整数值也为1000。基本上,在这个数据包中,我传达了两件事——所选客户机是谁以及与每个客户机关联的int值

我的问题存在于口译方面(客户端)。为了解释这种特殊类型的数据包,我使用以下方法:

    + (NSMutableDictionary *)infoFromData:(NSData *)data atOffset:(size_t) offset
{
    size_t count;

    NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:8];

    while (offset < [data length])
    {
        NSString *peerID = [data cnl_stringAtOffset:offset bytesRead:&count];
        offset += count;

        NSNumber *number = [NSNumber numberWithInteger:[data cnl_int32AtOffset:offset]];
        offset += 4;

        [info setObject:number forKey:peerID];
    }

    return info;
}
- (int)cnl_int32AtOffset:(size_t)offset
{
    const int *intBytes = (const int *)[self bytes];
    return ntohl(intBytes[offset / 4]);
}
此方法应该读取数据包中的可变长度字符串,将偏移量设置为peerID字符串后面的空字节填充后的字节,然后返回读取的字符串。然后将“amount”设置为方法为字符串读取的字节数(返回到第一个方法后,它将成为count的新值)。然后将“offset”和“count”加在一起,成为新的“offset”-从这里开始解释数据包的int部分。将上述参数传递给以下方法:

    + (NSMutableDictionary *)infoFromData:(NSData *)data atOffset:(size_t) offset
{
    size_t count;

    NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:8];

    while (offset < [data length])
    {
        NSString *peerID = [data cnl_stringAtOffset:offset bytesRead:&count];
        offset += count;

        NSNumber *number = [NSNumber numberWithInteger:[data cnl_int32AtOffset:offset]];
        offset += 4;

        [info setObject:number forKey:peerID];
    }

    return info;
}
- (int)cnl_int32AtOffset:(size_t)offset
{
    const int *intBytes = (const int *)[self bytes];
    return ntohl(intBytes[offset / 4]);
}
此方法旨在返回在数据包当前偏移量值处读取的32位(4字节)int值。我相信当偏移量是一个不能被4整除的数字时,这个方法存在问题。在本例中,正确解释了第一个int值1000,并在while循环的第一次迭代中返回32作为偏移量。然而,在第二次迭代期间,解释的int值为909377536(从读取数据包中的字节36340000而不是字节000003E8中获得),这可能是由于该迭代期间的偏移量被设置为47(不能被4整除)。在解释上述类别中的32位int之后,在第一个方法中,将4添加到偏移量中,以说明4字节(32位int)。如果我关于不可被零整除的偏移量的直觉是正确的,任何解决这个问题的建议都将受到极大的赞赏。我一直在寻找一种解决这个问题的方法已经有一段时间了,也许新鲜的眼睛会有所帮助。谢谢你的帮助

不可移植的版本(由于许多原因未定义行为):

半便携版本有点棘手,但您似乎可以假设
int32\t
是“通常的”两个补码表示(无陷阱表示,无填充位),因此:

//强制转换对于防止void*上的算术运算是必需的,void*是非标准的。
const uint8_t*p=(const uint8_t*)[自字节]+偏移量;
//强制转换确保结果类型足够大,可以容纳移位的值。
//我们使用uint32_t来防止UB在切换到符号位时出现。

uint32_t n=((uint32_t)p[0]准确地解决了我的问题!非常感谢你的帮助!你是人类中的上帝!因此我可以完全理解这些信息,以便将来可能出现的问题,你知道有什么好的参考资料可以更深入地解释不可移植版本和可移植版本之间的差异吗?编辑为包括半可移植版本(应该可以在具有相关类型的平台上工作)。主要问题是指针对齐不正确以及从无符号到有符号的转换,这两者都可能是未定义的行为。例如,GCC和LLVM具有编译器选项,允许它假设从未发生有符号溢出,例如
(int32_t)UINT32_MAX
为正。
// The cast is necessary to prevent arithmetic on void* which is nonstandard.
const uint8_t * p = (const uint8_t *)[self bytes]+offset;
// The casts ensure the result type is big enough to hold the shifted value.
// We use uint32_t to prevent UB when shifting into the sign bit.
uint32_t n = ((uint32_t)p[0]<<24) | ((uint32_t)p[1]<<16) | ((uint32_t)p[2]<<8) | ((uint32_t)p[3]);
// Jump through some hoops to prevent UB on "negative" numbers.
// An equivalent to the third expression is -(int32_t)~n-1.
// A good compiler should be able to optimize this into nothing.
return (n <= INT32_MAX) ? (int32_t)n : -(int32_t)(UINT32_MAX-n)-1;