【问题标题】:Tcp server only taking one command. Need to flush recv buffer?Tcp 服务器只接受一个命令。需要刷新 recv 缓冲区?
【发布时间】:2016-04-03 06:13:15
【问题描述】:

我能够将“插入数据”命令发送到 tcp 服务器,它会按照预期执行。我希望服务器一个接一个地执行多个命令。目前,如果我发送“插入数据”,然后按回车键,然后发送“鲍勃”,它不应该做任何事情,服务器会响应,就像我再次发送“插入数据”一样。如果您认为我应该发布完整的源代码,请在 cmets 中告诉我。截图:http://imgur.com/UNRFb5n

#define buf 2000
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    ssize_t read_size;
    char *message , client_message[buf];
    //char *contents;
    //contents = "hello";
    //strcpy(mess,contents);
    //Send some messages to the client
    message = "Greetings! I am your connection handler\n";
    write(sock , message , strlen(message));

    message = "Now type something and i shall repeat what you type \n";
    write(sock , message , strlen(message));

    //Receive a message from client
    while( (read_size = recv(sock , client_message , buf , 0 )) > 0 )
    {
        //write(sock , client_message , strlen(client_message));
        char start_char[] = "start";
        char insert_demo_char[] = "insert_demo";
        char *inserting = "Inserting Data\n";
        char *complete = "Task Complete\n";
        if(strcmp(message, start_char))
        {
            printf("Starting...\n");
            //start();
            //printf("it works");
            //fflush( stdout );
        }
        if(strcmp(message, insert_demo_char))
        {
            write(sock , inserting , strlen(inserting));
            printf("Inserting data\n");
            insert_demo();
            write(sock, complete, strlen(complete));
            printf("Finished Inserting Data\n");
        }
    }
    if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    //Free the socket pointer
    free(socket_desc);

    return 0;
}

【问题讨论】:

    标签: sockets tcp


    【解决方案1】:
    while( (read_size = recv(sock , client_message , buf , 0 )) > 0 )
    {
        [...]
        if(strcmp(message, start_char))
    

    在将数据接收到 client_message 后,您将改为检查名为 message 的缓冲区。由于您没有将 recv() 放入该缓冲区,因此它当然没有改变。

    还要注意 strcmp() 如果两个字符串相等则返回 0,如果两个字符串不同则返回非零;你可能在你的 if(strcmp()) 测试中倒退了(我不确定你想要什么行为)。

    【讨论】:

    • 无论如何,client_message 不能保证空终止,所以在它上面使用 strcmp() 是 UB。
    • 此外,如果传入的文本行在多个 recv() 调用中接收到多个部分,则程序将无法正常工作。
    【解决方案2】:

    由于 TCP 是八位字节流服务,并且不能发送长于一个字节的应用程序级消息,因此从客户端发送“插入数据”可能会导致 recv() 调用使用以下任何一种方式加载缓冲区:

    i
    in
    ins
    inse
    inser
    insert
    insert 
    insert d
    insert da
    insert dat
    insert data
    

    在应用程序级消息不完整的情况下,需要多次调用 recv() 才能接收消息的剩余字节。

    请注意,如果 recv() 恰好在一次调用中返回了所有数据,则发送“插入数据\0”只会在缓冲区中产生一个以空字符结尾的字符数组,这就是 recv( ) 是确定传输二进制数据时加载了多少字节的唯一方法:在这样的缓冲区上使用 strXXX 调用是 UB。你可以在传输文本时使用'read_size'来确保文本是空终止的,因此如果空终止符不在缓冲区中,则防止UB:

    while( (read_size = recv(sock , client_message , buf-1 , 0 )) > 0 )
    client_message[read_size]:=\0;
    

    .. 至少会为您提供一个“client_message”,它保证为空终止,尽管它不会帮助 strcmp() 无法识别缓冲区中的部分应用程序级消息。

    要传输大于一个字节的应用程序消息,您需要一个基于 TCP 的协议,该协议可以从字节流中解析出消息。

    【讨论】:

    • 感谢您的回答。你知道我可以学习任何在线书籍,以便我可以学习如何解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2019-03-19
    • 2016-01-10
    • 2016-08-05
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多