Pergunta

  1. Você tem vários adaptadores de rede.
  2. Vincule um soquete UDP a uma porta local, sem especificar um endereço.
  3. Receba pacotes em um dos adaptadores.

Como você obtém o endereço IP local do adaptador que recebeu o pacote?

A questão é: "Qual é o endereço IP do adaptador receptor?" não o endereço do remetente que obtemos no

receive_from( ..., &senderAddr, ... );

chamar.

Foi útil?

Solução

Você poderia enumerar todos os adaptadores de rede, obter seus endereços IP e comparar a parte coberta pela máscara de sub-rede com o endereço do remetente.

Como:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}

Outras dicas

Bom dia,

Presumo que você tenha feito sua ligação usando INADDR_ANY para especificar o endereço.

Se for esse o caso, então a semântica de INADDR_ANY é tal que um soquete UDP é criado na porta especificada em todas as suas interfaces.O soquete receberá todos os pacotes enviados para todas as interfaces na porta especificada.

Ao enviar usando este soquete, a interface de número mais baixo é usada.O campo de endereço do remetente de saída é definido como o endereço IP da primeira interface de saída usada.

A primeira interface de saída é definida como a sequência quando você executa um ifconfig -a.Provavelmente será eth0.

HTH.

obrigada Roubar

A solução fornecida por timbó assume que os intervalos de endereços são exclusivos e não se sobrepõem.Embora geralmente seja esse o caso, não é uma solução genérica.

Há uma excelente implementação de uma função que faz exatamente o que você está atrás fornecido no livro de Steven "Unix network programming" (seção 20.2) Esta é uma função baseada em recvmsg(), em vez de recvfrom().Se o seu soquete tiver a opção IP_RECVIF habilitada então recvmsg() retornará o índice da interface na qual o pacote foi recebido.Isso pode então ser usado para procurar o endereço de destino.

O código fonte está disponível aqui.A função em questão é 'recvfrom_flags()'

Infelizmente, as chamadas de API sendto e recvfrom são fundamentalmente quebradas quando usadas com soquetes vinculados a "Qualquer IP" porque não possuem campo para informações de IP local.

Então, o que você pode fazer sobre isso?

  1. Você pode adivinhar (por exemplo, com base na tabela de roteamento).
  2. Você pode obter uma lista de endereços locais e vincular um soquete separado a cada endereço local.
  3. Você pode usar APIs mais recentes que oferecem suporte a essas informações.Há duas partes para isso: primeiro você deve usar a opção de soquete relevante (ip_recvif para IPv4, ipv6_recvif para IPv6) para informar à pilha que deseja essas informações.Então você tem que usar uma função diferente (recvmsg no Linux e vários outros sistemas do tipo Unix, WSArecvmsg no Windows) para receber o pacote.

Nenhuma dessas opções é ótima.Adivinhar obviamente produzirá respostas erradas às vezes.A vinculação de soquetes separados aumenta a complexidade do seu software e causa problemas se a lista de endereços locais for alterada se o seu programa estiver em execução.As APIs mais recentes são a solução técnica correta, mas podem reduzir a portabilidade (em particular, parece que WSArecvmsg não está disponível no Windows XP) e pode exigir modificações na biblioteca wrapper de soquete que você está usando.

Editar parece que eu estava errado, parece que a documentação do MS é enganosa e que WSArecvmsg está disponível no Windows XP.Ver https://stackoverflow.com/a/37334943/5083516

ssize_t
     recvfrom(int socket, void *restrict buffer, size_t length, int flags,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int socket, struct msghdr *message, int flags);

[..]
     If address is not a null pointer and the socket is not connection-oriented, the
     source address of the message is filled in.

Código real:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

espero que isto ajude.

Experimente isto:

gethostbyname("localhost");
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top