UNIX Network Programming a ceci à dire à ce sujet même:
Avec un socket UDP, cependant, l'adresse IP de destination ne peut être obtenue en réglant l'option prise IP_RECVDSTADDR
pour IPv4 ou l'option prise IPV6_PKTINFO
pour IPv6 puis en appelant recvmsg
au lieu de recvfrom
.
bibliothèque socket Ruby a recvmsg
qui est un peu plus facile à utiliser que la fonction C sous-jacente, mais doit encore un peu de travail pour obtenir les informations nécessaires. L'adresse IP de destination est incluse dans le tableau des données auxiliaires renvoyées par recvmsg
. Voici une version de votre code adapté pour utiliser recvmsg
et obtenir l'adresse de destination pour IPv4:
require 'socket'
require 'ipaddr'
sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
# Set the required socket option:
sock.setsockopt :IPPROTO_IP, :IP_RECVDSTADDR, true
sock.bind(Addrinfo.udp('0.0.0.0', 2400))
while(true)
sockset = IO.select([sock])
sockset[0].each do |sock|
mesg, sender, _, *anc_data = sock.recvmsg
# Find the relevant data and extract it into a string
dest = IPAddr.ntop(anc_data.find {|d| d.cmsg_is?(:IP, :RECVDSTADDR)}.data)
puts "Data: #{mesg}, Sender: #{sender.ip_address}, Destination: #{dest}"
end
end
Et voici une version pour IPv6. Il y a aussi une option de socket RECVPKTINFO
, qui peut avoir été remplacée par PKTINFO
- selon votre système, vous devrez peut-être l'utiliser à la place.
require 'socket'
sock = Socket.new(Socket::AF_INET6, Socket::SOCK_DGRAM, 0)
# Set the socket option for IP6:
sock.setsockopt :IPPROTO_IPV6, :IPV6_PKTINFO, true
sock.bind(Addrinfo.udp('0::0', 2400))
while(true)
sockset = IO.select([sock])
sockset[0].each do |sock|
mesg, sender, _, *anc_data = sock.recvmsg
# Find and extract the destination address
dest = anc_data.find {|d| d.cmsg_is?(:IPV6, :PKTINFO)}.ipv6_pktinfo_addr
puts "Data: #{mesg}, Sender: #{sender.ip_address}, Destination: #{dest.ip_address}"
end
end
Ruby fournit également un Socket.udp_server_loop
method, ce qui donne le message et un objet UDPSource
au bloc que vous fournissez, et cet objet source a un champ local_address
. Looking at the source cela semble vérifier les données PKTINFO
comme je le fais ci-dessus pour obtenir l'adresse de destination pour les demandes IPv6, mais pas pour IPv4. Cette méthode se lie individuellement à toutes les adresses IP disponibles et utilise simplement l'adresse de l'interface entrante pour les demandes IP4, ce qui peut ne pas être exact pour un weak end system model. Cependant, il pourrait être plus simple pour vous d'utiliser Socket.udp_server_loop
.
Mais l'adresse IP locale n'est-elle pas "172.16.5.110" dans votre exemple? –