Multiple Clients Broadcasting on Same UDP Socket in C

Viewed 485

I am implementing some sort of auction. 5 users are connected to the same port using a UDP socket on the same address (INADDR_BROADCAST) and same port (udp_port) assigned previously by server.c. Each of them has 10 seconds to offer a price. If 10s pass, the turn will be passed to the next person. Here is how the socket is initialized:

udp_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_sockfd < 0)
    error("ERROR opening socket\n");
    
int broadcast_en = 1, opt_en = 1;
setsockopt(udp_sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast_en, sizeof(broadcast_en)); //set broadcasting
setsockopt(udp_sockfd, SOL_SOCKET, SO_REUSEPORT, &opt_en, sizeof(opt_en));
        
bc_adr.sin_family = AF_INET;
bc_adr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
bc_adr.sin_port = htons(udp_port);

if (bind(udp_sockfd, (struct sockaddr *) &bc_adr, sizeof(bc_adr)) < 0) 
    error("ERROR on binding");


printf("I am connected to the UDP Socket now\n\n");

How I handle the scenario above is with fd_set

    signal(SIGALRM, sig_handler); //Register signal handler
    printf("Auction beginning...\n");
    alarm(1);
    int mx = -1, ans;

    while (1)
    {
        
        FD_ZERO(&current_sockets);
        FD_SET(udp_sockfd, &current_sockets);
        FD_SET(STDIN, &current_sockets);  //standard input 

        if ((select(udp_sockfd + 1, &current_sockets, NULL, NULL, NULL) < 0) && (turn_cnt > 5)) //max_fd is udp_sockfd
            perror("ERROR on select");

        
        if (FD_ISSET(STDIN, &current_sockets)) 
        {
            bzero(buffer, 255);
            fgets(buffer, 255, stdin);

            int price = atoi(buffer);

            if (price > mx)
            {
                mx = price;
                ans = turn_cnt;
            }

            bzero(buffer, 255);
            strcat(buffer, "Person with turn ");
            char c[2] = {turn_cnt + '0', '\0'};
            strcat(buffer, c);
            strcat(buffer, " offered price ");
            
            char d[10]; //digits of price
            int sz = 0;
            while (price)
            {
                d[sz++] = '0' + (price % 10);
                price /= 10; 
            }         
            char rd[10];
            for (int i = sz - 1 ; i >= 0 ; i--)
                rd[sz - 1 - i] = d[i];
            rd[sz] = '\n';
            rd[sz + 1] = '\0';
        
            strcat(buffer, rd);
            
            sendto(udp_sockfd, buffer, strlen(buffer), 0,(struct sockaddr *)&bc_adr, sizeof(struct sockaddr_in));

            
        }

        if (FD_ISSET(udp_sockfd, &current_sockets)) //something broadcasted on udp_sockfd
        {
            bzero(buffer, 255);
            socklen_t bc_adr_len = sizeof(bc_adr);
            int n = recvfrom(udp_sockfd, buffer, 255, 0, (struct sockaddr *)&bc_adr, &bc_adr_len);
            if (n < 0)
                error("ERROR on reading broadcasted message\n");
            printf("BROADCASTED MESSAGE: %s\n", buffer);
            fflush(stdout);
        }

        if (turn_cnt == 5)
            break;
    }
    
    printf("The winner is user %d with price offer %d\n", ans, mx);

There weird thing happening is that, when some user broadcasts its price with some sort of message like: "Person with turn 1 offered price 11" using the sendto() function, this message is not received by the other clients until themselves enter their price. For example here is the terminal output of the 3rd client in the queue when he/she enters his/her price:

I am connected to the UDP Socket now

Auction beginning...
Person number 1 in queue has 10 seconds to offer his/her price...
Time is up!
Person number 2 in queue has 10 seconds to offer his/her price...
Time is up!
Person number 3 in queue has 10 seconds to offer his/her price...
22
BROADCASTED MESSAGE: Person with turn 1 offered price 11

BROADCASTED MESSAGE: Person with turn 2 offered price 43

BROADCASTED MESSAGE: Person with turn 3 offered price 22

The lines starting with "BROADCASTED MESSAGE" corresponding the first and second client, are not being printed on time. They are being printed only when the third client has entered his/her offer which is 22.

The output terminal for the second client is like this:

I am connected to the UDP Socket now

Auction beginning...
Person number 1 in queue has 10 seconds to offer his/her price...
Time is up!
Person number 2 in queue has 10 seconds to offer his/her price...
43
BROADCASTED MESSAGE: Person with turn 1 offered price 11

BROADCASTED MESSAGE: Person with turn 2 offered price 43

Again it can be seen that the first BROADCAST MESSAGE is not being printed on time.

I have been working on this for two days now and I seriously have no idea why isn't the sendto() method being detected by the other clients on-time. Could someone please help me with this? I would like to have the message (price offer) broadcasted for ALL clients simultaneously so they could see what other prices has been offered before their turn.

Edit: I have edited some parts of my code as Remy Lebeau said in the comments:

    struct sockaddr_in bc_adr_sendto, bc_adr_recvfrom;

    bc_adr_recvfrom.sin_family = AF_INET;
    bc_adr_recvfrom.sin_addr.s_addr = htonl(INADDR_ANY); 
    bc_adr_recvfrom.sin_port = htons(udp_port);

    bc_adr_sendto.sin_family = AF_INET;
    bc_adr_sendto.sin_addr.s_addr = htonl(INADDR_BROADCAST); 
    bc_adr_sendto.sin_port = htons(udp_port);

    
    if (bind(udp_sockfd, (struct sockaddr *) &bc_adr_recvfrom, sizeof(bc_adr_recvfrom)) < 0) 
        error("ERROR on binding");

...

    sendto(udp_sockfd, buffer, strlen(buffer), 0,(struct sockaddr *)&bc_adr_sendto, sizeof(struct sockaddr_in)); 

...

    socklen_t bc_adr_len = sizeof(bc_adr_recvfrom);
    int n = recvfrom(udp_sockfd, buffer, 255, 0, (struct sockaddr *)&bc_adr_recvfrom, &bc_adr_len);

But still there is no difference in the result.

Edit: Here is the sig_handler used for alarm:

void sig_handler(int signum)
{ 
    if (turn_cnt != 0)
        printf("Time is up!\n");
    printf("Person number %d in queue has 10 seconds to offer his/her price...\n", ++turn_cnt);
    alarm(10);
}
0 Answers
Related