C Socket TCP,将数组发送到服务器并循环响应客户端

C Socket TCP, send array to server and response back to client in loop

我对套接字和 TCP 很陌生,我正在尝试向服务器发送一个 Int 数组,进行一些排序和计算,然后将结果发送回客户端并重复。

我尝试了几种不同的方法,要么关闭客户端后得到结果,要么陷入死循环。

在客户端到达 EOF 之前继续从客户端读取的正确方法是什么?

这是我的服务器代码。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char const *argv[]) {
    struct sockaddr_in server, client;
    int sock, csock, readSize, addressSize;
    char buf[256];

    bzero(&server, sizeof(server));
    server.sin_family = PF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(5999);

    sock = socket(PF_INET, SOCK_STREAM, 0);
    bind(sock, (struct sockaddr*)&server, sizeof(server));
    listen(sock, 5);

    addressSize = sizeof(client);
    csock = accept(sock, (struct sockaddr *)&client, &addressSize);

    int values[5];

    while (read(csock, values, sizeof(values))) {

        // Some sorting and calculating here

        for (int i = 0; i < 5; i++) {
            printf("%d ", values[i]);
        }
    }
    close(sock);
    return 0;
}

这是我的客户端代码。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char const *argv[]) {
    struct sockaddr_in server;
    char buf[256];
    int sock;

    bzero(&server, sizeof(server));
    server.sin_family = PF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(5999);

    sock = socket(PF_INET, SOCK_STREAM, 0);
    connect(sock, (struct sockaddr *)&server, sizeof(server));

    while (1) {
        int values[5] = {0};

        for (int i = 0; i < 5; i++) 
            scanf("%d", &values[i]);
        
        write(sock, values, sizeof(values));
    }
    return 0;
}

感谢您的帮助!

在 Linux 上,我观察到如果客户端使用 Ctrl-C 终止,则服务器会在 read() returns 0 表示 EOF 时退出。如果给客户端一个 Ctrl-D,流的错误状态被设置,并且这个和所有未来的 scanf 调用失败而不设置 values。这意味着 values 保留它们的零初始化,在无限循环的每次迭代中发送到服务器。

Per @user207421,我猜 read() 是如何实现的 recv() 可能会 return 在 windows 上出错以表示错误。在这种情况下,服务器将循环使用原始代码。

在任何一种情况下,我都为大部分 calsl 添加了错误检查(您也应该为 inet_addr() 添加它),并且如果 read() returns 服务器将终止 - 1 或 0:

服务器:

#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>

int main(int argc, char const *argv[]) {
    struct sockaddr_in server, client;
    int sock, csock;
    socklen_t addressSize;

    bzero(&server, sizeof(server));
    server.sin_family = PF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(5999);

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1) {
        printf("socket: %s\n", strerror(errno));
        return 1;
    }
    if(bind(sock, (struct sockaddr*)&server, sizeof(server)) == -1) {
        printf("bind: %s\n", strerror(errno));
        return 1;
    }
    if(listen(sock, 5) == -1) {
        printf("listen: %s\n", strerror(errno));
        return 1;
    }

    addressSize = sizeof(client);
    csock = accept(sock, (struct sockaddr *)&client, &addressSize);
    if(csock == -1) {
        printf("listen: %s\n", strerror(errno));
        return 1;
    }

    int values[5];
    ssize_t n;
    while ((n = read(csock, values, sizeof(values)))) {
        printf("read %zd\n", n);
        if(n <= 0) break;
        for (int i = 0; i < n / sizeof(*values); i++) {
            printf("%d ", values[i]);
        }
        printf("\n");
    }
    close(sock);
    return 0;
}

和客户:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

int main(int argc, char const *argv[]) {
    struct sockaddr_in server;
    char buf[256];
    int sock;

    bzero(&server, sizeof(server));
    server.sin_family = PF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(5999);

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1) {
        printf("socket: %s\n", strerror(errno));
        return 1;
    }
    if(connect(sock, (struct sockaddr *)&server, sizeof(server)) == -1) {
        printf("connect: %s\n", strerror(errno));
        return 1;
    }


    while (1) {
        int values[5] = {0};

        for (int i = 0; i < 5; i++) {
            int r = scanf("%d", &values[i]);
            if(r == EOF) {
                return 0;
            }
        }
        ssize_t n = write(sock, values, sizeof(values));
        if(n == -1) {
            printf("write: %s\n", strerror(errno));
            return 1;
        }
        printf("wrote %zd\n", n);
    }
    return 0;
}

这是服务器的输出:

$ ./server 
read 20 bytes
1 2 3 4 5 

和客户端(注意;客户端不发送部分数据):

$ ./client 
1
2
3
4
5
wrote 20
1