我的 handle_clients 函数有什么问题

What is wrong with my handle_clients function

对套接字编程还很陌生,所以我的问题来了。怎么了?我的功能是从 telnet 会话中获取输入,然后当您按 'enter' 时,它应该会中断 while 循环。但它不是出于某种原因。我也不知道为什么,我尝试了各种方法,但到目前为止,我尝试过的任何方法都没有用。

</p> <pre><code>void handle_clients(socket,address) int *socket; const char *address; { char msg[256]; char cmd[128]; int bytes; memset(msg,0,sizeof(msg)); memset(cmd,0,sizeof(cmd)); while(1) { send(*socket,"CMD >> ",7,0); bytes = 0; while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) { if(bytes < 0) { sprintf(msg,"Error: receiving from %s.\r\n", address); send(*socket,msg,strlen(msg),0); break; } if(cmd[bytes] == 10 || cmd[bytes] == 13) { break; } } if(strcmp(cmd,"exit") == 0) { break; } else if(strcmp(cmd,"help") == 0) { sprintf(msg,"Commands: [exit,cmd,help]\r\n"); send(*socket,msg,strlen(msg),0); } else if(strcmp(cmd,"cmd") == 0) { memset(cmd,0,sizeof(cmd)); send(*socket,"Enter command: ",15,0); bytes = 0; while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) { if(bytes < 0) { sprintf(msg,"Error: receiving from %s.\r\n", address); send(*socket,msg,strlen(msg),0); break; } if(cmd[bytes] == 10 || cmd[bytes] == 13) { break; } } system(cmd); } else { sprintf(msg,"Unknown command.\r\n"); send(*socket,msg,strlen(msg),0); } memset(msg,0,sizeof(msg)); memset(cmd,0,sizeof(cmd)); } }

这个逻辑有问题:

 while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) {
        if(bytes < 0) {

        }
 }

bytes 将始终大于零,因此 if(bytes<0){} 块永远不会 执行。

您可能想将其更改为

 while((bytes = recv(*socket,cmd,sizeof(cmd),0))) {
        if(bytes < 0) {

        }
 }

如果bytes为0,则不会进入while循环

it should go break the while loop. But it doesn't for some reason.

除了我的同行指出的问题外,我认为您的具体查询的答案在于嵌套的 while 循环和 strcmp 中缺少的 \r\n 个字符.

由于 while 循环是嵌套的,因此 break 可能会在容器循环保留时打破嵌套循环 - 因此您将在下一次迭代中返回到下一个嵌套循环。

例如:

while(1) {
    send(*socket,"CMD >> ",7,0);
    bytes = 0;
    while((bytes = recv(*socket,cmd,sizeof(cmd),0))) {
        if(bytes < 0) {
            sprintf(msg,"Error: receiving from %s.\r\n",
                address);
            send(*socket,msg,strlen(msg),0);
            break; /* <= WHICH LOOP ARE WE BREAKING? */
        }
        if(cmd[bytes] == 10 || cmd[bytes] == 13) {
            break; /* <= WHICH LOOP ARE WE BREAKING? */
        }
    }
    // ...
 }

这是 goto 可能是您朋友的情况之一...

...虽然我确实认为在您去那里之前可能需要对您的代码进行更好和更优雅的解决方案和更改。

此外,如果要覆盖现有缓冲区,重新读取数据有什么意义?

我发现它几乎(在这种情况下)更方便并且可能忽略不完整的可能情况 TCP/IP packets/commands.

在这种特定情况下,似乎可以假设如果命令没有以新行结尾,则说明出了点问题,我们可以断开连接。这样的短命令应该在一个 TCP/IP 数据包中传递。即:

while(1) {
    send(*socket,"CMD >> ",7,0);
    bytes = 0;
    bytes = recv(*socket,cmd,sizeof(cmd),0);
    if(!bytes) { // closed by peer
       close(*socket);
       return;
    }
    if(bytes < 0 || cmd[bytes-1] == 10 || cmd[bytes-1] == 13) {
       if(errno == EINTR)
         continue;
       sprintf(msg,"Error: receiving from %s.\r\n",
                   address);
       close(*socket);
       return;
    }
    if(strcmp(cmd,"exit\r\n") == 0) {
        break;
    } else if(strcmp(cmd,"help\r\n") == 0) {}
    // ...
 }

此代码显然忽略了在单个 recv 中读取多个命令的可能性(即缓冲区为 "help\r\ncmd\r\nX\r\nexit\r\n")...但你会在某个时候解决这个问题。