【问题标题】:Strange looping with socket communication带有套接字通信的奇怪循环
【发布时间】:2013-12-04 21:27:04
【问题描述】:

我是套接字编程的新手,在调试以下代码时遇到了麻烦:

客户:

#define SIZE sizeof(struct sockaddr_in)

int main(int argc, char* argv[]) {
    printf("Starting setup\n");
    int sockfd;
    int adder;
    int sum;
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(7013);
    inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr);

    printf("Setup complete\n");

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket call failed.\n");
        return EXIT_FAILURE;
    }
    else{
        printf("socket: %i", sockfd);
    }

    //connect the socket
    if (connect(sockfd, (struct sockaddr*) &server, SIZE) == -1) {
        perror("Connect call failed");
        return EXIT_FAILURE;
    }

    //Send and receive
    while (!feof(stdin)) {
        printf("Input an integer \n");
        adder = atoi(fgets(intChar, 11, stdin));
        if ((send(sockfd, &adder, 11, 0)) == -1) {
            perror("Send error");
        }
        if (recv(sockfd, &sum, 1, 0) > 0) {
            printf("%d", sum);
        }
        else {
            printf("Server has died \n");
            close(sockfd);
            return EXIT_FAILURE;
        }
    }
    return EXIT_SUCCESS;
}

服务器:

int sum = 0;
int numconnections = 0;

int main(int argc, char* argv[]) {
    int sockfd;
    int newsockfd;
    int adder = 0;
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(7013);
    server.sin_addr.s_addr = INADDR_ANY;

    printf("Starting up. \n");
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    //Free port
    int on = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    if (sockfd == -1) {
        perror("Socket call failed. \n");
        return EXIT_FAILURE;
    }

    //bind address
    if (bind(sockfd, (struct sockaddr*) &server, sizeof(server)) == -1) {
        perror("Bind call failed. \n");
        return EXIT_FAILURE;
    }

    //listen
    if (listen(sockfd, 5) == -1) {
        perror("Listen call failed. \n");
        return EXIT_FAILURE;
    }
    while (numconnections < 2) {
        //accept a connection
        printf("ready to accept connections\n");
        if ((newsockfd = accept(sockfd, NULL, NULL)) == -1) {
            perror("Accept call failed. \n");
            continue;
        }
        printf("New connection detected");
        numconnections++;
        //spawn child to deal with it
        if (fork() == 0) {
            while (recv(newsockfd, &adder, 1, 0) > 0) {
                printf("Sum is %d \n", sum);
                printf("Adder is %d \n", adder);
                sum += adder;
                printf("Sending sum %d \n", sum);
                send(newsockfd, &sum, 1, 0);
            }
            close(newsockfd);
            return EXIT_SUCCESS;
        }
    }
    close(newsockfd);
        close(sockfd);

    return EXIT_SUCCESS;
}

无论我是在同一台机器上运行程序还是单独运行程序,当服务器接收到一个套接字时,它都会连续添加大约 10 次数字,几乎就像套接字在循环一样。

这是我从客户端提交 3 后的一些示例输出:

Starting up. 
ready to accept connections
New connection detectedready to accept connections
New connection detectedSum is 0 
Adder is 3 
Sending sum 3 
Sum is 3 
Adder is 0 
Sending sum 3 
Sum is 3 
Adder is 0 
Sending sum 3 
Sum is 3 
Adder is 0 
Sending sum 3 
Sum is 3 
Adder is 77 
Sending sum 80 
Sum is 80 
Adder is 11 
Sending sum 91 
Sum is 91 
Adder is 64 
Sending sum 155 
Sum is 155 
Adder is 0 
Sending sum 155 
Sum is 155 
Adder is 3 
Sending sum 158 
Sum is 158 
Adder is 0 
Sending sum 158 
Sum is 158 
Adder is 0 
Sending sum 158 

在客户端,我最初取回了 3,但后来我得到了一些无意义的数字,例如 4197123。

我有一种强烈的感觉,我错过了一些明显的东西。提前致谢。

【问题讨论】:

  • while (recv(newsockfd, &amp;adder, 1, 0) &gt; 0) { 使用 recv() 的返回值是实际收到的字节数。第三个论点也是错误的。
  • 哦,我明白了,第三个参数是缓冲区大小,所以我应该使用 sizeof(int)。
  • 至少。或者调用之间的缓冲,这是必要的,因为 TCP 没有消息边界:流可以在任何时候被分解。
  • 我把while循环改成了if语句,现在服务端好了,只打印了一次。但是,客户端仍然会收到初始总和,然后是一个无意义的值。
  • if ((send(sockfd, &amp;adder, 11, 0)) == -1) { 也非常错误(客户端)您发送的是 int,而不是字符串。

标签: c sockets fork


【解决方案1】:
while (recv(newsockfd, &adder, 1, 0) > 0) { ...

使用recv()的返回值是实际接收到的字节数。第三个论点也是错误的。它至少应该是 sizeof(int)。或者你可以缓冲调用之间的部分接收,这是必要的,因为 TCP 没有消息边界:流可以在任何时候被分解。 (请参阅我的草图缓冲here

您还应该更改 send(); 的第三个参数; send() 类似。

adder = atoi(fgets(intChar, 11, stdin));
if ((send(sockfd, &adder, 11, 0)) == -1) { ...

(client) 也是非常错误的,您发送的是 int,而不是字符串。

最后:不要使用feof(),至少不要这样。 feof() 将在 fgets() 失败后返回非零值,NULL 参数可能已经崩溃 atoi()。

【讨论】:

  • 我去掉了客户端循环,反正没必要。
猜你喜欢
  • 2013-11-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-14
  • 2019-05-25
相关资源
最近更新 更多