简体   繁体   中英

C - Simple ipv6 udp server using select to listen on multiple ports. Receiving message from one port, not the other

Here is my code.

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <stdio.h>
#include <string.h>

int max(int socket_handle[]);

int main( void )
{
   int       max_clients_allowed = 2;
   int       socket_handle[max_clients_allowed];
   int       client_handle[max_clients_allowed];
   struct    sockaddr_in6 server_address[max_clients_allowed];
   struct    sockaddr_in6 client_address[max_clients_allowed];
   char      buffer[1000];
   socklen_t client_length;
   fd_set    read_handles;
   struct    timeval timeout_interval;
   int       bytes_received;
   int       port_number = 9000;
   int       retval;
   int       i;


   printf("Hello, human.\n");

   for (i = 0; i < max_clients_allowed; i++)
   {
       printf("Creating socket%d on port: %d\n", i, port_number + i);
       socket_handle[i] = socket(PF_INET6,SOCK_DGRAM,0);
       memset( &server_address[i], 0, sizeof( server_address[i] ) );
       server_address[i].sin6_family = AF_INET6;
       server_address[i].sin6_addr=in6addr_any;
       server_address[i].sin6_port=htons( port_number + i );

       if(bind( socket_handle[i], (struct sockaddr *)&server_address[i], sizeof( server_address[i] )) < 0)
       {
           perror("Unable to bind.");
           return -1;
       }
       else
       {
           printf("Bind %d successful.\n", i);
       }

   }



   while (1) {

       FD_ZERO(&read_handles);
       FD_SET(socket_handle[0], &read_handles);
       FD_SET(socket_handle[1], &read_handles);
       timeout_interval.tv_sec = 2;
       timeout_interval.tv_usec = 500000;
       retval = select(max(socket_handle) + 1, &read_handles, NULL, NULL, &timeout_interval);
       if (retval == -1)
       {
           printf("Select error\n");
           //error
       }
       else if ((retval = 0))
       {
           printf("timeout\n");
       }
       else
       {
           //good
           client_length = sizeof(struct sockaddr*);
           for (i = 0; i < max_clients_allowed; i++)
           {
              if (FD_ISSET(socket_handle[i], &read_handles))
              {
                  if((bytes_received = recvfrom(socket_handle[i],buffer,sizeof(buffer),0,(struct sockaddr *)&client_address[i], (socklen_t*)&client_length)) < 0)
                  {
                     perror("Error in recvfrom.");
                     break;
                  }
                  printf("\nData received:");
                  printf("\n--------------\n");
                  printf("%s", buffer);
            }
           }
       }
   }
}

int max(int socket_handle[])
{
    if (socket_handle[0] > socket_handle[1])
    {
        return socket_handle[0];
    }
        return socket_handle[1];
}

This code is supposed to bind to port 9000 and 9001. It them uses select to see which sockets has incoming data, and then prints the message.

I'm assuming it has something to do with my recvfrom function. I've tried playing around with the parameters with no avail.

Another problem might be when I am setting up the sockets, I am using sin6.addr = in6addr_any. I'm pretty sure PF_INET6 and AF_INET6 are right, but that could be an issue too. I've been playing with this for a bit but I can't find the bug. I would be really grateful if someone could point out my mistake so I could fix it. I know I'm on the cusp of getting this finished.

This is a homework problem, the teacher gave us the test program and all it does is simply send a message on port 9000.

When calling recvfrom() , you are setting the client_length to the wrong value on input. It needs to be set to sizeof(client_address[I]) instead. You also need to reset the client_length each time you call recvfrom() .

When you print the received buffer , you need to take bytes_received into account since the buffer will not be null-terminated (unless the client is sending null-terminated data).

Try this instead:

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <stdio.h>
#include <string.h>

int main( void )
{
    int       max_servers = 2;
    int       server_handle[max_servers];
    int       max_server_handle = 0;
    struct    sockaddr_in6 server_address[max_servers];
    struct    sockaddr_in6 client_address[max_servers];
    char      buffer[1000];
    socklen_t client_length;
    fd_set    read_handles;
    struct    timeval timeout_interval;
    int       bytes_received;
    int       port_number = 9000;
    int       retval;
    int       i;

    printf("Hello, human.\n");

    for (i = 0; i < max_servers; i++)
    {
        printf("Creating socket %d on port: %d\n", i, port_number + i);

        server_handle[i] = socket(PF_INET6, SOCK_DGRAM, 0);
        if (server_handle[i] < 0)
        {
            perror("Unable to create socket.");
            return -1;
        }

        if (server_handle[i] > max_server_handle)
            max_server_handle = server_handle[i];

        memset( &server_address[i], 0, sizeof( server_address[i] ) );
        server_address[i].sin6_family = AF_INET6;
        server_address[i].sin6_addr = in6addr_any;
        server_address[i].sin6_port = htons( port_number + i );

        if (bind( server_handle[i], (struct sockaddr *)&server_address[i], sizeof( server_address[i] )) < 0)
        {
            perror("Unable to bind.");
            return -1;
        }

        printf("Bind %d successful.\n", i);
    }

    while (1)
    {
        FD_ZERO(&read_handles);
        for (i = 0; i < max_servers; i++)
            FD_SET(server_handle[i], &read_handles);

        timeout_interval.tv_sec = 2;
        timeout_interval.tv_usec = 500000;

        retval = select(max_server_handle + 1, &read_handles, NULL, NULL, &timeout_interval);
        if (retval == -1)
        {
            printf("Select error\n");
            //error
        }
        else if (retval == 0)
        {
            printf("timeout\n");
        }
        else
        {
            //good
            for (i = 0; i < max_servers; i++)
            {
                if (FD_ISSET(server_handle[i], &read_handles))
                {
                    client_length = sizeof(client_address[i]);

                    if ((bytes_received = recvfrom(server_handle[i], buffer, sizeof(buffer), 0, (struct sockaddr *)&client_address[i], &client_length)) < 0)
                    {
                        perror("Error in recvfrom.");
                        break;
                    }

                    printf("\nData received on socket %d:", i);
                    printf("\n--------------\n");
                    printf("%.*s", bytes_received, buffer);
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM