【问题标题】:Byte array containing integer and string representation包含整数和字符串表示的字节数组
【发布时间】:2013-08-29 08:43:32
【问题描述】:

我正在为我的 iPhone 制作一个 iOS 套接字客户端。我需要通过 tcp/ip 发送一些字节。一般的想法是,我想将多个值存储在一个字节数组中,以避免多次写入流。举个例子:

uint8_t buffer[1024]; // buffer to hold all data I'm sending

NSString *command = @"Broadcast"; // the actual message i want to send
int length = [command length]; // length of said message

现在,对于缓冲区数组中的前 4 个位置,我想放置长度变量,从 4 到 13,我想放置实际消息。我知道如何在服务器端对其进行解码,但我不太清楚如何将这些数据放入缓冲区数组中,所以我有一个包含我要发送的所有数据的数组。

非常感谢任何帮助!

【问题讨论】:

    标签: objective-c c byte bytearray bytebuffer


    【解决方案1】:

    考虑以下代码:

    // First, we get the C-string (NULL-terminated array of bytes) out of NSString.
    const char *cString = [command UTF8String];
    
    // The length of C-string (a number of bytes!) differs terribly from
    // NSString length (number of characters! Unicode characters are 
    // of variable length!).
    // So we get actual number of bytes and clamp it to the buffer
    // size (so if the command string occasionally gets larger than our
    // buffer, it gets truncated).
    size_t byteCount = MIN(BUFFER_SIZE - 4,
                           [command lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
    
    // Now we're using C type conversion to reinterpret the buffer as a
    // pointer to int32_t. The buffer points to some memory, it's up to us
    // how to treat it.
    *(int32_t *)buffer = byteCount;
    
    // And finally we're copying our string bytes to the rest of the buffer.
    memcpy(buffer + 4, cString, byteCount); 
    

    这段代码有一个警告——它使用主机字节顺序来存储uint32_t 变量,所以如果你通过网络传递这个缓冲区,固定你的字节顺序通常是一个好主意(网络历史上使用 big-字节序,尽管现在大多数计算机都是小字节序的)。

    要修复字节顺序,只需替换行

    *(int32_t *)buffer = byteCount;
    

    *(int32_t *)buffer = htonl(byteCount);
    

    并且不要忘记在其他计算机上处​​理此缓冲区时将字节顺序转换回来!

    【讨论】:

    • 您的答案似乎对我有用,但是我很难理解它的实际作用。您是否介意扩展示例,假设我想将消息的长度附加到缓冲区的末尾,然后再附加消息,我该怎么做?
    • @cnh1991 如果你想在缓冲区的最后写入长度,下面的代码将变为:*(uint32_t *)(buffer + 1020) = byteCount。它重新解释buffer + 1020,例如从 buffer 开始的 1020 个字符,作为指向 uint32_t 的指针。
    【解决方案2】:

    您可以将其作为 C 字符串发送:

    const char * cString = [command UTF8String];
    length = strlen(cString);
    
    for (int i = 0; i < length; ++i) {
        buffer[i + 4] = cString[i];
    }
    
    buffer[0] = length & 0xff;
    buffer[1] = (length >> 8)  & 0xff;
    buffer[2] = (length >> 16) & 0xff;
    buffer[3] = (length >> 24) & 0xff;
    

    【讨论】:

    • 这会将命令字符串添加到缓冲区中,就像我需要的那样。但是如何在缓冲区的前 4 个元素中放入字符串长度的字节表示?
    • 如果使用非 ASCII 字符,此代码将中断 - [NSString length] 返回字符数,而不是字节数。
    • @iHunter 好的,考虑到这一点。
    【解决方案3】:

    这不是生产代码,如果大小很大并且缺少错误检查,它会溢出。应该让您知道需要做什么。

    const int SIZE = 64;
    const int SIZE_OFFSET = 0;
    const int MESSAGE_OFFSET = 4;
    
    
    // Set up the buffer.
    Byte buffer[SIZE];
    for (int i = 0; i < SIZE; i++) {
        buffer[i] = 0;
    }
    uint8 *ptr; // Used to traverse data.
    
    NSString *command= @"Broadcast";
    
    // note: non ASCII characters, such as é,  will consume 2 bytes.
    NSData *data = [command dataUsingEncoding:NSUTF8StringEncoding];
    // uint32 ensures we get a 4 byte integer on non 32bit systems.
    uint32 dataLength = [data length] ; // Number of bytes stored in data.
    
    // Place dataLength into the first 4 elements of the buffer. Keep endianness in mind.
    *ptr = &dataLength;
    for (int8_t iterator = SIZE_OFFSET; iterator < sizeof(uint32) + SIZE_OFFSET; iterator++) {
        buffer[iterator] = ptr[iterator];
    }
    
    // todo, place data into buffer.
    

    【讨论】:

    • 为什么不使用memset 将缓冲区归零并使用memcpy 将字符串复制到缓冲区?
    猜你喜欢
    • 2013-08-04
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    相关资源
    最近更新 更多