C语言 - 使用select监听多个端口的简单IPv6 UDP服务器。从一个端口接收消息,而不是另一个端口。

3

这是我的代码。

#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];
}

这段代码应该绑定到9000和9001端口。然后使用select来查看哪些套接字有传入数据,然后打印消息。
我认为问题可能与我的recvfrom函数有关。我已经尝试过调整参数但无济于事。
另一个问题可能出现在设置套接字时,我使用sin6.addr = in6addr_any。我相当确定PF_INET6和AF_INET6是正确的,但这也可能是一个问题。我已经试了一段时间,但是找不到错误。如果有人能指出我的错误,让我可以修复它,我将不胜感激。我知道我即将完成它,这是一道作业题,老师给我们测试程序,它只是简单地在9000端口发送一条消息。

请在此展示你的代码--pastebin.com过载了,无法让我查看。 - Barmar
1
Pastebin现在无法访问。请将您的代码简化到最少,以演示问题,并编辑您的问题以在此处显示实际代码。 - Remy Lebeau
@Barmer 代码复制粘贴在这里 - Cool Joe
@Remy 谢谢,已经复制/粘贴代码到问题中。 - Cool Joe
1个回答

2

在调用recvfrom()时,你需要在输入时将client_length设置为sizeof(client_address[I]),而不是错误的值。每次调用recvfrom()时,还需要重置client_length

当你打印接收到的buffer时,需要考虑bytes_received,因为缓冲区不会以空字符结尾(除非客户端发送了以空字符结尾的数据)。

请尝试使用以下代码:

#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);
                }
            }
        }
    }
}

我的错误。我使用了IPv6版本。 - Cool Joe
除了底部的printf语句,这就是我在认为已经完成之前所拥有的,所有的调整都没有问题。它没有给我任何错误。这是输出:数据接收:\n --------------\n 发送到端口9000\n 数据接收:\n --------------\n“发送到端口9000”是从客户端发送的消息。它也应该说“发送到端口9001”。因此,recv函数两次都成功,但我没有得到消息的字符串。Wireshark显示两个数据包都是有效的。编辑:我希望我能在这里放置换行符.. - Cool Joe
我已经将它传入了。它没有起作用。我从你的代码中复制的唯一一行是这个:"printf("%.*s", bytes_received, buffer);" 感谢你的帮助!:] - Cool Joe
那可能是您客户端代码的问题。请更新您的问题,附上最新的服务器代码并添加您的客户端代码。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接