2

我正在尝试编写将与任何可以建立套接字连接的标准客户端(例如 telnet 客户端)通信的服务器

它最初是一个回显服务器,当然不需要担心网络字节顺序。

我熟悉ntohs、ntohl、htons、htonl函数。如果我要传输 16 位或 32 位整数,或者要发送的字符串中的字符是 2 或 4 个字节的倍数,这些本身就很棒。

我想创建一个对字符串进行操作的函数,例如:

str_ntoh(char* net_str, char* host_str, int len)
{
    uint32_t* netp, hostp;
    netp = (uint32_t*)&net_str;
    for(i=0; i < len/4; i++){
         hostp[i] = ntoh(netp[i]);
    }
}

或类似的东西。上面的事情假设字大小是 32 位。我们不能确定发送机器上的字大小不是 16 位还是 64 位,对吗?

对于客户端程序,例如 telnet,它们必须在发送前使用 hton*,在接收数据后使用 ntoh*,对吗?

编辑:对于那些因为 1-char 是字节序无关紧要的字节的人:

int main(void)
{
    uint32_t a = 0x01020304;
    char* c = (char*)&a;
printf("%x %x %x %x\n", c[0], c[1], c[2], c[3]);

}

运行这段代码。我的输出如下:

$ ./a.out
  4 3 2 1

那些使用 powerPC 芯片组的人应该得到“1 2 3 4”,但我们这些使用 intel 芯片组的人应该看到我上面得到的大部分内容。

4

4 回答 4

17

也许我在这里遗漏了一些东西,但是您是在发送字符串,即字符序列吗?那么你就不需要担心字节顺序了。这仅适用于整数位模式。字符串中的字符始终按“正确”顺序排列。

编辑:

Derrick,为了解决您的代码示例,我在 Intel i7(小端)和旧的 Sun Sparc(大端)上运行了您的程序的以下(略微扩展)版本

#include <stdio.h>
#include <stdint.h> 

int main(void)
{
    uint32_t a = 0x01020304;
    char* c = (char*)&a;
    char d[] = { 1, 2, 3, 4 };
    printf("The integer: %x %x %x %x\n", c[0], c[1], c[2], c[3]);
    printf("The string:  %x %x %x %x\n", d[0], d[1], d[2], d[3]);
    return 0;
}

如您所见,我在您的整数打印输出中添加了一个真正的 char 数组。

小端英特尔 i7 的输出:

The integer: 4 3 2 1
The string:  1 2 3 4

以及大端 Sun 的输出:

The integer: 1 2 3 4
The string:  1 2 3 4

您的多字节整数确实在两台机器上以不同的字节顺序存储,但是 char 数组中的字符具有相同的顺序。

于 2009-12-19T21:23:10.660 回答
4

使用发布的函数签名,您不必担心字节顺序。它接受一个只能处理 8 位字符的 char*。每个字符一个字节,就不会出现字节顺序问题。

如果您以 UTF16 或 UTF32 编码发送 Unicode,您只会遇到字节顺序问题。并且发送机器的字节序与接收机器的不匹配。简单的解决方案是使用 UTF8 编码。这是大多数文本通过网络发送的内容。面向字节,它也没有字节顺序问题。或者您可以发送BOM。

于 2009-12-19T21:35:22.430 回答
2

如果您想将它们作为 8 位编码发送(您使用的事实char意味着这就是您想要的),则无需进行字节交换。但是,对于非 ASCII 字符的不相关问题,使相同的字符> 127在连接的两端出现相同的情况,我建议您以UTF-8之类的方式发送数据,它可以代表所有 unicode 字符并且可以被安全地视为 ASCII 字符串。基于默认编码获取 UTF-8 文本的方式因平台和您使用的库集而异。

如果您要发送 16 位或 32 位编码...您可以包含一个带有字节顺序标记的字符,另一端可以使用该字符来确定字符的字节顺序。或者,您可以假设网络字节顺序并按照您的建议使用htons()或。htonl()但如果您想使用char,请参阅上一段。:-)

于 2009-12-19T21:33:53.080 回答
1

在我看来,函数原型与其行为不符。您传入了一个 char *,但随后将其转换为 uint32_t *。而且,更仔细地看,您正在转换指针的地址,而不是内容,所以我担心您会得到意想不到的结果。也许以下会更好:

arr_ntoh(uint32_t* netp, uint32_t* hostp, int len)
  {
  for(i=0; i < len; i++)
    hostp[i] = ntoh(netp[i]);
  }

我基于这样的假设,即您真正拥有的是一个 uint32_t 数组,并且您想在所有这些上运行 ntoh() 。

我希望这是有帮助的。

于 2009-12-20T03:59:29.527 回答