在同一个 UDP 数据包中发送 ASCII 字符和 int

Sending ASCII characters and int in the same UDP packet

我需要通过 UDP 套接字发送一个数据包,其中将有一个以 ASCII 字符串形式编写的六位数字,在换行符之后,相同的数字,但以字节为单位 int,如下所示:31 32 33 34 35 36 0A 00 01 E2 40 对应于 123456\n(123456) - 整数在括号中。到目前为止,我可以发送我的字符串和我的换行符,但是当涉及到 int 时,我得到 0 个字节被写入缓冲区并且我的 int 缓冲区数组中没有任何内容被发送。此外,如果我检查 int 缓冲区数组的文本内容,它有奇怪的“Fs”数量:00 01 FFFFFFE2 40

这是我的 UDP 客户端:

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>


char buf[11];

int main(int argc, char **argv)
{
    struct sockaddr_in adr;
    int sock, r;
    unsigned int port;
    char abcd[512];
    char intBuff[4];
    unsigned int index = 123456;
    unsigned int networkHost;
    networkHost = htonl(index);

    memcpy(intBuff, (char*)&networkHost,sizeof(uint32_t));
    printf("Int buffer: ");
      for(int i=0; i<sizeof(uint32_t); i++){
        printf("%02X ", intBuff[i]); //Output is 00 01 FFFFFFE2 40
    }

    int x1 = sprintf(buf,"%s\n","123456"); 
    printf("\n1st data write: %i\n", x1); //7 bytes are written


    int x2 = sprintf(&buf[x1], "%s",intBuff); 
    printf("2nd data write: %i\n", x2); //0 bytes are written


    //SERVER
    printf("IP: ");
    scanf("%s", abcd);
    printf("PORT: ");
    scanf("%u", &port);

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    adr.sin_family = AF_INET;
    adr.sin_port = htons(port);
    adr.sin_addr.s_addr = inet_addr(abcd);


    r = sendto(sock,
               buf,
               11,
               0,
               (struct sockaddr*) &adr,
               sizeof(adr));

    close(sock);
    return 0;
}

问题

出现奇怪的值是因为你的char数组是signed,当你传递给printf时,编译器将它解释为signed整数。

不要使用sprintf(...,"%s", ...)复制可能包含零字节的二进制数据,因为"%s"格式在到达[=18=]空字符时会突然停止复制。


解决方案

  1. 使用unsigned char,因此编译器在将数据传递给printf时不会将其解释为signed整数。
  2. 使用memcpyintBuff复制到buf

代码示例


#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>

int main() {
    unsigned char buf[11];
    unsigned char intBuff[sizeof(uint32_t)];
    uint32_t index = 123456;
    uint32_t networkHost;
    networkHost = htonl(index);

    memcpy(intBuff, &networkHost, sizeof(networkHost));

    for (int i=0; i < sizeof(intBuff); i++){
      printf("%02x ", intBuff[i]);
    }

    int x1 = sprintf(buf,"%s\n","123456"); 
    printf("\n1st data write: %i\n", x1); // 7 bytes are written


    // It is certain that the write is sizeof(intBuff) in size.
    memcpy(&buf[x1], intBuff, sizeof(intBuff));

    int total_len = x1 + sizeof(intBuff);

    printf("Packed data: ");
    for (int i = 0; i < total_len; i++) {
      printf("%02x ", buf[i]);
    }

    putchar('\n');
}

输出

ammarfaizi2@integral:/tmp$ gcc x.c -o x 
ammarfaizi2@integral:/tmp$ ./x
00 01 e2 40 
1st data write: 7
Packed data: 31 32 33 34 35 36 0a 00 01 e2 40 
ammarfaizi2@integral:/tmp$ 

表示整数的字节通常可以具有任何值,因为整数具有各种值。所以一个字节可能为零。然后使用 printf%s 将这些字节写入缓冲区将在零字节处停止,因为 %s 需要一个字符串。字符串的定义是,它是一个以零字节结尾的字符序列。

对于您使用的值,第一个字节是零,因此 printf 立即停止,不写入任何字节。

不是使用printf将字节复制到缓冲区,而是直接用memcpy复制它们:

memcpy(&buf[x1], &networkHost, sizeof networkHost);

您根本不需要 intBuff,可以将其从您的程序中删除。