1

I'm very new to socket and TCP, I'm trying to send an array of Int to the server, do some sorting and calculating, then send back the result to the client and repeat.

I tried a few different ways, I either got the result after I close the client or got into a infinite loop.

What is the proper way to keep reading from the client until the client hit EOF?

Here is my server code.

#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;
}

And here is my client code.

#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;
}

Thanks for your help!

10
  • "or got into a infinite loop" -- Did the infinite loop occur in the server or client or both? Commented Sep 25, 2021 at 3:02
  • @AndreasWenzel It only occur in the server. Commented Sep 25, 2021 at 3:08
  • "I either got the result after I close the client" -- Who is 'I"? The client or the server? If it is the client, how can the client receive the result after it has been closed? And how did you close the client? With CTRL-C? Commented Sep 25, 2021 at 3:09
  • 2
    Check errors code. Commented Sep 25, 2021 at 3:19
  • 4
    All your networking calls potentially return errors. socket, accept, read, write, bind etc. Commented Sep 25, 2021 at 3:32

1 Answer 1

2

On Linux, I observed that if client is terminated with Ctrl-C, then server exits when read() returns 0 to signify EOF. If client is given a Ctrl-D, the stream's error state is set and this and all future scanf calls fail without setting values. This means values retain their zero initialization, which is sent to server in each iteration of the infinite loop.

Per @user207421, recv() which I guess how read() is implemented may return on error on windows to signify and errors. In this case, server would loop with the original code.

In either case, I added error checking for most of calsl (you should also add it for inet_addr()), and the server will terminate if read() returns either -1 or 0:

server:

#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;
}

and client:

#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;
}

and here is the output from the server:

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

and the client (note; client doesn't send partial data):

$ ./client 
1
2
3
4
5
wrote 20
1
Sign up to request clarification or add additional context in comments.

12 Comments

It doesn't 'mean 0 values were being sent to server (forever).' Nothing is sent at all after the client exits. The server receives 0 values from recv() forever, but not because they were sent: it is because recv() knows the socket is at end of stream because of the client disconnect.
In the original client code values is initialized to {0} in the loop, scanf is terminated with ctrl-d, which means this and subsequent calls to scanf return EOF, and the initialized values are subsequently sent to the server.
@user207421 You are not wrong, but I also made server changes to address read() failing or returning 0 on eof. If I am still missing something let me know.
@user207421 client does NOT exit when ctrl-d is entered to scanf with original code.
In comments section, OP stated that they were using CTRL-C to close client, not CTRL-D.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.