user4128992
user4128992

Reputation:

UDP server only responding to one client

I have some C code for a UDP server and client (It must be UDP, not TCP). I am facing trouble while trying to send a message to all the connected clients.

When the server receives a message from a client, it can answer back to the very same client, but it's not serving the other connected clients. Can someone please help me with this ?

server.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "lib/colors/colors.h"
#include "lib/simlist/simclist.h"



typedef char* string; // to make life easier

#define PORT "9034"

void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

    int main(void){

        fd_set master;    
        fd_set read_fds;  
        int fdmax;        
        int listener;     
        int newfd;     

        struct sockaddr_storage remoteaddr; 
        socklen_t addrlen;

        char buf[1024];    
        int nbytes;

        char remoteIP[INET6_ADDRSTRLEN];

        int yes = 1;       
        int i, j, rv;

        struct addrinfo hints, *ai, *p;

        FD_ZERO(&master);    
        FD_ZERO(&read_fds);

        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_PASSIVE;
        rv = getaddrinfo(NULL, PORT, &hints, &ai);

    /* simlist initialisation */
        list_t clients;
        typedef struct client{
            fd_set socket_number;
            char *username[100];
        } client;

        list_init(&clients);

        client new_client;
        string client_username;
    /* end of simlist */

        if ( rv != 0) {
            fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
            exit(1);
        }

        for(p = ai; p != NULL; p = p->ai_next) {

            listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

            if (listener < 0) {
                continue;
            }

            setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

            if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
                close(listener);
                continue;
            }
            break;
        }

        if (p == NULL) {
            printf( "failed to bind\n");
            exit(2);
        }

        freeaddrinfo(ai);

        if (listen(listener, 10) == -1) {
            perror("listen");
            exit(3);
        }

        FD_SET(listener, &master);
        fdmax = listener;

        for(;;) {
            read_fds = master;
            if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
                perror("select");
                exit(4);
            }

            for(i = 0; i <= fdmax; i++) {

                if (FD_ISSET(i, &read_fds)) {

                    if (i == listener) {
                        addrlen = sizeof remoteaddr;
                        newfd = accept(listener,
                            (struct sockaddr *)&remoteaddr,
                            &addrlen);

                        if (newfd == -1) {
                            perror("accept");
                        } else {
                            FD_SET(newfd, &master);
                            if (newfd > fdmax) {
                                fdmax = newfd;
                            }
                            // @TODO
                            // insert into list user, ip, port combination
                            printf("new connection from %s on socket %d\n",
                                inet_ntop(remoteaddr.ss_family,
                                    get_in_addr((struct sockaddr*)&remoteaddr),
                                    remoteIP, INET6_ADDRSTRLEN),
                                newfd);
                        }
                    } else {
                        nbytes = recv(i, buf, sizeof buf, 0);
                        printf("nb of bytes received : %d \n", nbytes);
                        if ( nbytes <= 0) {
                            if (nbytes == 0) {
                                printf("%s socket %d hung up \n", warning_msg(""), i);
                                // delete user from list
                            } else {
                                perror("recv");
                            }
                            close(i);
                            FD_CLR(i, &master);
                        } else {
                            // data received from client
                            for(j = 0; j <= fdmax; j++) {
                                // send to everyone!
                                if (FD_ISSET(j, &master)) {
                                    // except the listener and ourselves
                                    if ( j != listener || j != i) {
                                        printf("available sockets %d \n", j);
                                        printf("SENDING : %s\n", buf);
                                        send(j,buf,nbytes, 0);
                                        // if (send(j, buf, nbytes, 0) == -1) {
                                        //  perror("send");
                                        // }
                                    }
                                }
                            }
                        }

                    }
                }
            }
        }

        return 0;
    }

client.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "lib/colors/colors.h"

#define PORT "9034"

#define MAXDATASIZE 1024

void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[]){
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];

    if (argc != 3) {
        fprintf(stderr,"usage: ./client [hostname] [username] \n");
        exit(1);
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
            perror("client: socket");
        continue;
    }

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("client: connect");
        continue;
    }

    break;
}

if (p == NULL) {
    fprintf(stderr, "client: failed to connect\n");
    return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
printf("client: connecting to %s\n", s);

char *username = argv[2];
send(sockfd, username, MAXDATASIZE-1, 0);

while(1){
    char word[MAXDATASIZE];
    printf(">");
    fgets(word, sizeof(word), stdin);
    send(sockfd, word, MAXDATASIZE-1, 0);
    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    exit(1);
    }else{
        printf("RECEIVED : %s\n",buf);    
    }

}

freeaddrinfo(servinfo);


buf[numbytes] = '\0';

printf("client: received '%s'\n",buf);

close(sockfd);

return 0;
}

Upvotes: 1

Views: 513

Answers (2)

user207421
user207421

Reputation: 310840

I have some C code for a UDP server and client.

No you don't. This is a TCP server. You are specifying SOCK_STREAM; you are calling listen(), accept(), and connect(): it's TCP.

(It must be UDP, not TCP)

Then you need to start again.

I am facing trouble while trying to send a message to all the connected clients.

There are no connections in UDP.

Upvotes: 1

mfro
mfro

Reputation: 3335

The way you want it (send message to each connected client) needs to address each client individually. You can do that with looping over your connection table sending each client a message. That's not much different from what you have already.

If you want to do "real" broadcasting and if it doesn't matter if other not connected machines receive the message as well, look up broadcasting (only works within the same network segment if you do not have special IP helpers configured on your routers) and/or multicasting.

Upvotes: 1

Related Questions