0

I'm trying to create a server that can receive messages from multiple connected clients, but in my code, the recv() function always return -1. How can I make my server receive codes from the client?

This is my server. The recv() function is called in the while loop at the bottom.

I tried to use read(), but I couldn't find a way to make it unblocking. Is there any way to interpret this by using read()? If not, How can I fix this problem with recv() always returning -1, despite I have a new client connected and have a new message sent?

    /*------------------Header Files----------------------------------------------------------------------*/
#define _GNU_SOURCE

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>

#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<sys/stat.h>

#include<netinet/in.h>
#include<netinet/ip.h>

#include<arpa/inet.h>

/*-------------------Linked List------------------------------------------------------------------------*/
struct client_online{

        int client_socket;
        char* name;
        struct client_online* next;
};

/*-------------------Global Variables-------------------------------------------------------------------*/
struct client_online* first_client = NULL;

/*-------------------Main Function----------------------------------------------------------------------*/
int main(int argc, char* argv[]){

    // Cite: get help from office hour code
    // Creating the socket
    int server_socket;
    server_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if(server_socket < 0){
        perror("Error creating server socket");
        return -1;
    }

    // Server address
    struct sockaddr_in server_address;
    memset(&server_address, 0, sizeof(struct sockaddr_in));
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(atoi(argv[2]));
    server_address.sin_addr.s_addr = inet_addr(argv[1]);

    // Binding the socket
    int binder = bind(server_socket, (const struct sockaddr *) &server_address, sizeof(server_address));
    if(binder == -1){
            perror("Error calling bind");
            return -1;
    }

    // Listen to the socket
    int listener = listen(server_socket, 50);
    if(listener == -1){
            perror("Error calling listen");
            return -1;
    }

    // Client address
    struct sockaddr_in client_address;

    // Reading and writing
    int quit = 0;
    while(!quit){

        // Check if there is a new connection
        int client_address_size = sizeof(client_address);
        int each_client_socket = accept4(server_socket,
                     (struct sockaddr*) &client_address,
                         &client_address_size,
                     SOCK_NONBLOCK);

        // If there is a new connection, add client to linked list
        if(each_client_socket >= 0){

            if(first_client == NULL){
                first_client = malloc(sizeof(*first_client));
                first_client->client_socket = each_client_socket;
                first_client->name = (char*)malloc(100);
                strcpy(first_client->name,"User");
                first_client->next = NULL;

                free(first_client->name);
                free(first_client);
            }

            else{
                struct client_online* tracker = first_client;
                while(tracker->next != NULL){
                    tracker = tracker->next;
                }

                struct client_online* new_client;
                new_client = malloc(sizeof(*new_client));
                new_client->client_socket = each_client_socket;

                new_client->name = (char*)malloc(100);
                strcpy(new_client->name, "User");
                new_client->next = NULL;
                tracker->next = new_client;

                free(new_client->name);
                free(new_client);
            }
        }

        // Check if there are messages recieved
        struct client_online* checker = first_client;
        while(checker != NULL){

            char client_response[256];
            char toSend[256];

            bzero(client_response, sizeof(client_response));

            int receiver = recv(checker->client_socket,
                                client_response,
                                sizeof(client_response),
                                MSG_DONTWAIT);

            printf("%d\n", receiver);
            if(receiver > 0){
                printf("message received\n");
                snprintf(toSend, sizeof(toSend), "%s: %s\n", checker->name, client_response);

                struct client_online* sender = first_client;
                while(sender != NULL){

                    send(sender->client_socket, toSend, sizeof(toSend), MSG_DONTWAIT);
                }
            }

            checker = checker->next;
        }

        sleep(1);

    }

        return 0;
}

Here is my client

/*----------------------------------------------------Header Files----------------------------------------*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#include<fcntl.h>

#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<sys/stat.h>

#include<netinet/ip.h>
#include<arpa/inet.h>

#define _GNU_SOURCE
/*----------------------------------------------------Main Function--------------------------------------*/
int main(int argc, char* argv[]){

    // Seek help from office hour codes
    // Create the client socket
    int client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if(client_socket < 0){
        perror("Error creating client socket");
        return -1;
    }

    // Construct the address of the connection
    struct sockaddr_in client_address;
    memset(&client_address, 0, sizeof(struct sockaddr_in));
    client_address.sin_family = AF_INET;
    client_address.sin_port = htons(atoi(argv[2]));
    client_address.sin_addr.s_addr = inet_addr(argv[1]);

    // Connect the client to the server
    int connecter = connect(client_socket,
                    (const struct sockaddr*) &client_address,
                    sizeof(struct sockaddr_in));
    if(connecter < 0){
        perror("Error connecting to server");
    }

    // Reading and writing
    int quit = 0;
    while(!quit){

        // Read from command line
        char client_message[256];
        memset(&client_message, 0, sizeof(client_message));

        int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
        fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
        int reader = read(STDIN_FILENO, client_message, sizeof(client_message));

        if (reader > 0) {

            // Writing normal message
            send(client_socket, client_message, 1, MSG_WAITALL);
        }
        //
        sleep(1);

    }

    return 0;
}
NNNNNNN
  • 29
  • 1
  • 7
  • Is `errno` equal to `EAGAIN` when `recv` returns `-1`? – jxh Dec 07 '19 at 10:05
  • yes, errno == EAGAIN || errno == EWOULDBLOCK – NNNNNNN Dec 07 '19 at 10:08
  • Then you just need to read the instructions. In any case, it would really help if you extracted a [mcve] from your code. There's no need to dump your whole code here when large parts are irrelevant anyway. As a new user here, please also take the [tour] and read [ask]. – Ulrich Eckhardt Dec 07 '19 at 10:14

1 Answers1

0

Since you are passing MSG_DONTWAIT to your recv call, if there is nothing to receive from the client yet, the call will return an error to indicate that fact.

If you are using polling mechanism, like epoll, then you would typically wait for a readable notification. Once the notification is received, you can retry the recv call. I don't see any use of a polling mechanism in your code.

Alternatively, you can spawn a thread for each new connection, and use blocking calls to recv (omit the MSG_DONTWAIT flag).

jxh
  • 69,070
  • 8
  • 110
  • 193