0

I'm implementing a client/server in linux using C, after initiating both client and server, the server is waiting for a query from the client and that seems to be working, however, I would like for the server to be able to constantly wait for queries. Yet it keeps looping nonstop instead of waiting for a new query from the client.

server.c:

int main(void)
{
    int sockfd, newsockfd, portno, clilen, connfd = 0;
    struct sockaddr_in serv_addr, cli_addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        printf("socket failed\n");
        exit(0);
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
    {
        printf("setsockopt failed\n");
        exit(0);
    }

    memset((char *) &serv_addr, 0, sizeof(serv_addr));
    portno = 8888;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("bind failed\n");
        exit(0);
    }

    listen(sockfd, 5);

    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0)
    {
        printf("accept failed\n");
        exit(0);
    }

    printf("[Server] Connected\n");
    char query[BUFFER_SIZE];
    char result[BUFFER_SIZE];

    while (1)
    {
        connfd = read(newsockfd, query, 20);
        if (connfd > 0)
        {
            printf("success\n");
        }
        connfd = write(newsockfd, "I got your message", 18);
        if (connfd >= 0)
        {
            printf("write back worked\n");
        }
        //close(newsockfd);
        //close(sockfd);
        sleep (1);
    }

    printf("%d", connfd);
    printf("[Server] Done\n");
    return 0;
}

As you can see I've tried adding in close commands, but all they seem to do is to stop the connection entirely which means I'm not able to send queries at all after the first.

client.c:

int main(void)
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        printf("socket failed\n");
        exit(0);
    }

    portno = 8888;
    server = gethostbyname("localhost");
    if (server == NULL)
    {
        printf("gethostbyname failed\n");
        exit(0);
    }

    memset((char *)&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    memcpy((void*)&serv_addr.sin_addr.s_addr, (void*)server->h_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("connect failed\n");
        exit(0);
    }

    printf("[Client] Connected\n");

    char query[BUFFER_SIZE];
    char result[BUFFER_SIZE];

    while (1)
    {
        memset(query, 0, BUFFER_SIZE);
        fgets(query, BUFFER_SIZE, stdin);
        if(strncmp(query, "exit", 4) == 0)
        {
            break;
        }

        n = write(sockfd, query, sizeof(query));
        if (n < 0) {
            printf("can't write\n");
        }

        bzero(result, BUFFER_SIZE);
        n = read(sockfd, result, BUFFER_SIZE);
        if (n < 0) {
            printf("can't read back from server\n");
        }

        printf("%s\n", result);
        sleep(1);
    }
    close(sockfd);
    return 0;
}

With this code, the server just keeps on going and writes back to the client "I got your message" infinitely. How do I make it wait? Tried adding in close(newsockfd) but once I do that it only lets me contact the server once, and the second query from the client fails.

Barmar
  • 741,623
  • 53
  • 500
  • 612
reo
  • 13
  • 3
  • You are trying to use TCP as if it were a message protocol. It's not, it's a byte stream protocol. Your code has two states it can be in -- waiting for data from the user and waiting for data from the other side. But it has no intelligence to decide when to switch from one state to the other, effectively doing so randomly. – David Schwartz Apr 18 '19 at 20:31

1 Answers1

2

The problem is this in the client:

n = write(sockfd, query, sizeof(query));

sizeof(query) is the same as BUFFER_LEN. When the server does:

connfd = read(newsockfd, query, 20);

it will succeed BUFFER_LEN / 20 times for each query that the client sends. This isn't an infinite loop, but if BUFFER_LEN is large it will repeat many times.

The client shouldn't send the entire query buffer, just the line that was read from stdin. It should do:

n = write(sockfd, query, strlen(query));

Note also that there's no guarantee that a single call to read() in the server will read everything that the client has written, it might be split up across multiple calls. Since your input is delimited with newline characters (because you use fgets() in the client), you should keep reading until you get the newline.

For more information, see difference between sizeof and strlen in c

Barmar
  • 741,623
  • 53
  • 500
  • 612