【问题标题】:htonl/ntohl not correct value on second command?htonl/ntohl 第二个命令的值不正确?
【发布时间】:2015-03-05 19:07:55
【问题描述】:

编辑:老实说,我不知道错误发生在哪里,所以我将添加大部分相关代码,不确定这些是否有帮助

所以基本上我有两个基本的服务器和客户端进程。 用户指定一个命令,客户端进程将消息的长度发送给服务器,服务器执行命令并返回响应的消息长度。

这在第一个命令上效果很好(我连续尝试了两个 ls -la),第一个命令的值为 1028(正确的值),第二个命令的值为 1685223288(在客户端)不正确

使用以下代码完成写入:

server_handler() {
char str[5000];
char * token = NULL;
unsigned long totalSize = 0;
str[0] = "\0";
totalSize = htonl(totalSize); // Correct size already calculate
if((result = write(clientFD, (char *) &totalSize, sizeof(totalSize)) < 0))
{
     printf("Failed sending size to client\n");
     exit(-1);
}
//Here the server starts sending the results to the client
token = strtok(str, "\n"); // str array contains the results
while(token != NULL)
{
     token[strlen(token)] = '\n';
     write(clientFD, token, strlen(token));
     token = strtok(NULL, "\n);
}

读取在客户端进程中通过以下方式完成:

static void handle_reply() 
{
char * revBuf = 0;
unsigned long int bytesRead = 0;
unsigned long bufferlen = 0;
while(1) 
{
    result = read(socketFD, (char *) &bufferlen, sizeof(bufferlen));
    bufferlen = ntohl(bufferlen);
    recvBuf = malloc(bufferlen);
   //Here client starts reading results
    while(bytesread < bufferlen)
    {
        result = read(socketFD, recvBuf, bufferlen);
        printf("recvBuf: %s\n", recvBuf);
        bytesRead = strlen(recvBuf) + bytesRead;
    }
    free(recvBuf);
    bufferlen = 0;
   client_handler(); //calls Function that asks for new command
}
}

我的问题:为什么我在第一个命令之后收到错误的值?, 我已经验证了在这两种情况下,totalSize 在服务器端的值都是正确的。 写/读一定有问题?

我还在服务器上打印了 htonl(totalSize),它是 67371008。 但是客户端收到的值是 ntohl 之前的 2021093988。

【问题讨论】:

  • 这个问题的标题太错误了,太常见了,问题不可能发生,因为某些标准功能有问题,有可能……但真的不太可能。问题一定是你的代码,所以先怪它,如果结果是函数错误,那么你没有伤到任何人的眼睛......
  • 32 位服务器与 64 位客户端或相反?
  • 两者都在同一台计算机上运行以进行测试
  • 您可能需要验证result == sizeof(bufferlen) 的一件事。另一方面,您是否在两个“命令”之间发送数据?是否有可能,虽然您第一次说要发送 1028 个字节,但实际上发送的数量不同,导致您第二次引用的 read 从流中的不同位置读取,而不是您认为正在读取的位置?
  • 请注意,1028 和 67371008 彼此字节反转(0x4040x4040000)。与 1685223288 和 2021093988 相同(0x647277780x78777264,这也是文本字符串“drwx”或“xwrd”,其中第一个看起来像是来自 ls -l 的输出的一部分)...

标签: c sockets htonl


【解决方案1】:

以下代码将无法正常工作,因为您在修改字符串后再次调用strlen

token = strtok(str, "\n");
while(token != NULL)
{
    token[strlen(token)] = '\n';
    write(clientFD, token, strlen(token));
    token = strtok(NULL, "\n");
}

为了说明,假设str 最初是"hello\nworld\n"。用十六进制表示

 68 65 6c 6c 6f 0A 77 6f 72 6c 64 0A 00
                ^---- the first newline

strtok 之后是

 68 65 6c 6c 6f 00 77 6f 72 6c 64 0A 00
                ^---- strtok changed it to a NUL

token[strlen(token)] = '\n' 行之后

 68 65 6c 6c 6f 0A 77 6f 72 6c 64 0A 00
                ^---- you changed it back to a newline

所以现在 write 中的 strlen 将返回 12,因此 write 将发送 12 个字节,而不是您期望的 6 个字节。这可以通过调用strlen 来解决,就像这样

token = strtok(str, "\n");
while(token != NULL)
{
    size_t length = strlen(token);
    token[length] = '\n';
    write(clientFD, token, length);
    token = strtok(NULL, "\n");
}

【讨论】:

  • 虽然这并没有解决我的全部问题,但它确实解决了部分问题并帮助了我很多,我想我知道我现在需要做什么。谢谢!
【解决方案2】:

htonl 和 ntohl 是 32 位 ...

  uint32_t htonl(uint32_t hostlong);
  uint32_t ntohl(uint32_t netlong);

看看使用 64 位系统的程序处理大整数会发生什么。

#include <stdio.h>

int main(int argc, char** arg)
{
  unsigned long bufferlen = 0;
  unsigned long totalSize = 1024;
  sscanf(arg[1],"%lld",&totalSize);
  printf("%lld  %llx\n", totalSize,totalSize);

  totalSize = htonl(totalSize); // 32 <-> 64bits .
  bufferlen = ntohl(totalSize);

  printf("%lld %llx %lld %llx\n", totalSize,totalSize,bufferlen,bufferlen);

}

测试它:

./test 111111111111111
111111111111111  650e124ef1c7
-940487150 ffffffffc7f14e12 307163591 124ef1c7

【讨论】:

  • 不要认为这是我的问题,我在 VM 中的 32 位操作系统上为此(OpenIndiana)加上第一次的值是正确的,只有第二次被读取客户端它的值错误。
  • 我同意这可能不是你的问题。
猜你喜欢
  • 2016-08-23
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
  • 2019-01-12
相关资源
最近更新 更多