【问题标题】:Using unsigned char instead of char because of its range使用 unsigned char 而不是 char 因为它的范围
【发布时间】:2026-01-11 13:45:02
【问题描述】:

我一直在开发一个小型纯 C 客户端应用程序(我的第一个:/),它使用 TCP 套接字与服务器进行通信。服务器向我发送一个数据包(C 结构),其中第一个字节包含数据包的大小。

问题是服务器使用 unsigned char 来表示数据包的大小,因为 char 是有符号的(从 -128 到 +127),而 +127 不足以表示在某些数据包中可能高达 255 的大小。 => 我需要一个无符号字符缓冲区;

在Linux中,recv()函数的第二个参数是void *,这意味着我可以声明一个void *buffer,没有问题。但是 Windows (MinGW) 中的 recv() 有 char * 而不是 void *。这给了我警告“参数类型不匹配:不兼容的指针类型'char *'和'unsigned char *'”

这个问题能解决吗?这是代码。谢谢。

PS:我使用的是非阻塞套接字。

 int recvsize = 0;
unsigned char tmpsize;
int index = 0;
unsigned char *buffer;

while (1) {

    recvsize = recv(server, &tmpsize, sizeof(unsigned char), 0); // every packet starts with one byte where is its length

    if (recvsize > 0 ) {
         buffer = malloc(tmpsize * sizeof(unsigned char)); //memory allocation according to the size of packet
         buffer[0] = tmpsize--; //get back the size value to the buffer
         recvsize = 0;


        do { //loop over and over until you do not have all bytes of the packet
            recvsize = recv(server, &buffer[++index], tmpsize, 0);

            if (recvsize == 0)
                break;


            tmpsize -=recvsize;
            index += recvsize;

        } while (tmpsize != 0);

    }
sleep(50);
}

【问题讨论】:

  • char 可能已在您的平台上签名。标准将此留给实现,一般来说,在不同系统之间传输数据时(大多数时候也在同一系统中),使用stdint.h类型和适当的序列化是首选方式。否则 tarpit 正在等待。
  • 注意:sizeof(unsigned char) 始终为 1,因此不需要 ... * sizeof(unsigned char)。如果代码要注意变量大小的缩放,建议buffer = malloc(tmpsize * sizeof *buffer)

标签: c sockets tcp char unsigned


【解决方案1】:

只需将指针转换为正确的类型。所以使用:

(char *) (&buffer[++index])

另外,您为什么要通过在睡眠循环中重复非阻塞操作来创建阻塞方案?要么使用阻塞套接字,要么使用非阻塞套接字,但不要在中间创建一些虚假的东西。 (例如,如果恶意或慢速客户端只向您发送一个字节,您将使用recv。)

最后,为什么在第一次调用recv 时只读取一个字节?无论如何,您都需要其余的数据,那么为什么要让内核以微小的方式将其提供给您呢?为什么不尽可能多地读取字节,并且如果幸运的话,可以避免再次调用recv

【讨论】:

  • "为什么你在第一次调用中只读取一个字节" 嗯,也许可能有多个消息,并且通过读取“尽可能多的字节”,可能无法获取多个或部分消息,并且那么必须管理它吗?
  • @chux 是的,当然。这就是 TCP 的本质。现在,他正在强制内核执行此操作。他已经处理了部分消息。
  • 感谢您的快速回复!我忘了删除这个睡眠语句,我只是想测试一些东西。对此感到抱歉。我只读取一个字节,然后读取数据包的其余部分,因为我不想解析一个大缓冲区 [512] 或 [1024],其中可能有很多数据包或一些不完整的数据包。我懒得写代码了。
  • @Cpt.Rambler 没有睡眠,你只会在等待数据的紧密循环中烧毁 CPU。
  • @DavidSchwartz 我知道,你是对的。那么,这个 do-while 循环,你对“假中间物”有什么看法?
最近更新 更多