【问题标题】:Client - Server Socket C Code: Server doesn't execute code after "read" until another line is sent客户端 - 服务器套接字 C 代码:服务器在“读取”后不执行代码,直到发送另一行
【发布时间】:2019-04-01 07:10:34
【问题描述】:

我正在编写一些代码来创建客户端-服务器连接。客户端向服务器发送字符串,服务器应该根据发送的内容解析和打印字符串。

客户端代码:

// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080

int main(int argc, char const *argv[]) {
    struct sockaddr_in address;
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    size_t len = 0;
    char *buffer = NULL;
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 and IPv6 addresses from text to binary form
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    if (connect(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    while(1) {
        getline(&buffer, &len, stdin);
        printf("Line sent: %s", buffer);
        send(sock, buffer, strlen(buffer), 0);
    }
}

服务器代码:

/*Required Headers*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>

int main()
{

    char str[100];
    int listen_fd, comm_fd;

    struct sockaddr_in servaddr;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    bzero( &servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htons(INADDR_ANY);
    servaddr.sin_port = htons(8080);

    bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    listen(listen_fd, 10);

    comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);

    while(1)
    {
        bzero( str, 100);

        read(comm_fd,str,100);

        printf("Received: %s",str);
        if(strncmp(str, "NEW", 3) == 0)
        {
            printf("Client - NEW");
        }
        else if(strncmp(str, "FILE", 4) == 0)
        {
            printf("Client - FILE");
        }
        else if(strncmp(str, "NAME", 4) == 0)
        {
            strtok(str, ": ");
            printf("NAME: %s", str);
        }
        else if(strncmp(str, "DESCRIPTION", 11) == 0)
        {
            strtok(str, ": ");
            printf("DESCRIP: %s", str);
        }
        else if(strncmp(str, "PRINTER", 7) == 0)
        {
            strtok(str, ": ");
            printf("PRINTER: %s", str);
        }

    }
}

我期望发生的是,当我从客户端向服务器发送“NEW”时,服务器会打印“Client - NEW”。然后,当我发送“FILE”时,服务器会打印“CLIENT - FILE”。会发生一次发送延迟。因此,当我发送 NEW 时,服务器会打印“Received: NEW”,但不会进入 if 检查以打印“CLIENT - NEW”。然后,当我发送“FILE”时,服务器会打印“Client - NEWRecieved: FILE”。

我在这里做错了什么?

【问题讨论】:

  • 可能是行缓冲问题,在每个 printf 格式字符串的末尾添加一个\n
  • @tevemadar 该问题/答案中的哪些内容应该对这里的 OP 有所帮助?
  • @Ctx 人们误用了read,他们忽略了它的返回值,并假设它会读取一个“消息”,即他们一步就输入到另一端的内容。在您的回答中,您通过将事物视为基于行的协议来解决问题,但测试字符串“FILE”预测 OP 将在下一步尝试将其扩展为文件传输协议。所以是的,你帮助编写了一个聊天应用程序,只是我不认为他们正在编写一个聊天应用程序。最后OP仍然不知道如何使用read
  • @tevemadar 只需专注于 OP 提出的问题,并给他机会,让他自己解决其他问题。

标签: c sockets


【解决方案1】:

所以当我发送 NEW 时,服务器会打印“Received: NEW”

是的,就在这里:

printf("Received: %s",str);

但具体来说,您发送“NEW\n”,服务器会打印“Received: NEW\n”。这个换行符是相关的,因为它会触发行缓冲终端上的输出

但它不会进入 if 检查以打印“CLIENT - NEW”。

是的,它执行条件:

printf("Client - NEW");

但输出会被缓冲,直到下一个换行符被打印出来。

然后,当我发送“FILE”时,服务器会打印“Client - NEWRecieved: FILE”。

现在在您发送“文件”之后,它会被执行:

printf("Received: %s",str);

str 将“FILE\n”作为内容。这会刷新当前包含“Client - NEWRecieved: FILE\n”的输出缓冲区。此外

printf("Client - FILE");

被执行(但不输出,仅缓冲)并且进程迭代。

所以解决方法是,在每个 printf 格式字符串的末尾添加一个换行符“\n”(或者在简单的情况下使用 puts)。

printf("Received: %s\n",str); // Although "str" will usually contain a newline, but better play it safe

puts("Client - NEW");

此外,如果你有一个基于行的协议,你应该为你的套接字切换到缓冲输入:

comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
FILE *sock = fdopen(comm_fd, "r+");

然后逐行读取输入

while (1) {
    fgets(str, sizeof(str), sock);

【讨论】:

  • 真正的问题当然是(一如既往)假设消息边界。
  • @wildplasser 这不是他目前在这里提出的问题,但我还是解决了这个问题。也许这对他将来有帮助。当前的问题显然是行缓冲。
  • 还有bzero()的东西。这是防御性的。而且也非常错了。
  • @Ctx 你的解决方案解决了我的缓冲问题,谢谢!!
  • 这是不必要的,危险的,货物崇拜循环浪费。正确处理 read() 返回的结果将告诉您在哪里插入 NUL 终止符,读取不足 99 将确保 NUL 始终有空间并防止 UB 在读取 100 个字符时越界写入. 'multiple code sn-ps'都不好:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
相关资源
最近更新 更多