【问题标题】:C: Weird behaviour between client and serverC:客户端和服务器之间的奇怪行为
【发布时间】:2015-08-30 04:17:10
【问题描述】:

我正在用C编写一个服务器-客户端程序。客户端以5个字节的形式向服务器发送一个命令:第一个字节是一个操作,接下来的4个字节是执行操作的关键.

服务器看起来像这样:

int nowread, key;
while(1)
{
    char buffer[1024];
    int alreadyread = 0;
    do
    {
        nowread = read(socket,buffer+alreadyread,5-alreadyread);
        alreadyread += nowread;
    }
    while((nowread > 0) && (5-alreadyread > 0));

    if(nowread == -1 || nowread == 0)
    {
        printf("Error reading from client socket\n");
        exit(1);
    }

    key = (((int)buffer[1])<<24 | ((int)buffer[2])<< 16 | ((int)buffer[3]) << 8 | ((int)buffer[4]) << 0);

    printf("%d, key from server \n",key); // just for debugging


//DO COMMAND

我一直在通过让客户端发送 10 个命令来测试程序:

 op: 1, num: 645110
 op: 2, num: 419811
 op: 0, num: 115300
 op: 2, num: 792023
 op: 2, num: 146624
 op: 1, num: 842346
 op: 1, num: 450778
 op: 0, num: 550046
 op: 1, num: 284186
 op: 2, num: 691858

我从服务器获取:

-10, key from server 
-29, key from server 
-15772, key from server 
-41, key from server 
-64, key from server 
-9622, key from server 
-38, key from server 
-98, key from server 
284186, key from server 
-110, key from server 

如您所见,只有一个键匹配,这很奇怪(它们应该都匹配或不匹配)。我 100% 确定这是服务器端,而不是客户端的问题。有谁知道是什么原因造成的?

提前致谢。

编辑: 这是发送数据的代码

    uint32_t net_num = htonl(num);
    int nsent = 0;
    while (nsent < 4)
    {
        rc = write(sockfd,&net_num + nsent, 4 - nsent);
        if (rc <= 0)
        {
            printf("error! write() failed: %s\n", strerror(errno));
            break;
        }

        nsent += rc;
    }

    if (rc <= 0)
        break;

【问题讨论】:

  • 你如何发送数据?
  • 显示发送数据的代码非常重要。您可能会遇到字节顺序问题或其他微妙问题。
  • 你发送了四个字节,但接收到了五个,你是在给我们显示的数字之前发送一个字节吗?
  • 您的大多数密钥都是负数的事实使我认为您在将密钥转换为值的方式方面遇到了签名问题。尝试将buffer 的类型更改为unsigned char 的数组。
  • 此外,如果您希望能够传输负键,则需要更加小心,因为对有符号整数值的任何算术运算,其数学结果不在可表示的范围内目标类型产生未定义的行为。

标签: c ubuntu websocket server


【解决方案1】:

您正在以错误的方向处理缓冲区。您还需要将其从网络字节转换回来。 ntohl ( ) 就是这样做的。

像这样:

uint32_t key;
uint32_t result;

key = ( uint32_t )(( buffer [ 1 ] << 0 )  |
                   ( buffer [ 2 ] << 8 )  |
                   ( buffer [ 3 ] << 16 ) |
                   ( buffer [ 4 ] << 24 ));

result = ntohl ( key );

【讨论】:

  • 我认为你错了:OP 确实处理网络中的缓冲区以直接获取值。从他自己的数据来看,有一个传输是正确的:284186, key from server,如果字节顺序错误,情况就不会如此。错误来自使用char 数组而不是unsigned char。你的方法有同样的问题,而且它在大端平台上不起作用:你应该这样阅读keykey = *(uint32_t*)(buf + 1);,但地址需要正确对齐。 OPs 方法要简单得多。为了保持一致性,他也应该在客户端代码中使用它。
【解决方案2】:

char 类型在您的系统上已签名,因此当您在服务器端计算 key 值时,当您将它们转换为 int 时,字节值会进行符号扩展。不需要显式转换,如果没有它们,结果将是相同的。

您必须将buffer 设为unsigned char 的数组:

unsigned char buffer[1024];

客户端代码也是错误的,它只有在nsent0 时才有效。如果出于某种不可能的原因 write 只写入 13 字节之间,您将尝试从内存中传输字节超出 net_num 变量的末尾,调用未定义的行为:

写(sockfd, &net_num + nsent, 4 - nsent);

你应该这样做:

write(sockfd, (unsigned char*)&net_num + nsent, 4 - nsent);

或者更好,为了与服务器代码保持一致:

char buffer[5];
ssize_t rc, nsent;

buffer[0] = code;
buffer[1] = (num >> 24) & 255;
buffer[2] = (num >> 16) & 255;
buffer[3] = (num >>  8) & 255;
buffer[4] = (num >>  0) & 255;

for (nsent = 0; nsent < 5; nsent += rc) {
    rc = write(sockfd, buffer + nsent, 5 - nsent);
    if (rc <= 0) {
        printf("error! write() failed: %s\n", strerror(errno));
        break;
    }
}

if (rc <= 0)
    break;

【讨论】:

    猜你喜欢
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 2023-03-12
    • 2011-02-10
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    相关资源
    最近更新 更多