receiving UDP packets send to 127.0.0.1 when using SO_REUSEADDR

最后都变了- 提交于 2019-12-04 03:46:14

It seems like what you want is to hard code the broadcast address without worrying about what actual IP addresses are in use by the machine. Your first problem is that since this is a new application you should be using multicast instead of broadcast. Then you can use a special multicast address which can be the same everywhere, regardless of what address the machine actually has. I assume all these apps are running on the same machine.

Here's an example program written in Perl. You should be able to adapt the code fairly easily. Start a few copies in different windows to see how it works. Basically it forks a sender and receiver and sends the datetime and pid of the sender. You'll need to install the Socket::Multicast package from CPAN in order to run it.

#!/usr/bin/perl -w
# This example is a reimplementation of Steven's sendrecv Multicast example from UNP
use strict;
use diagnostics;
use Socket;
use Socket::Multicast qw(:all); # Has to be installed from CPAN

my $sendSock;

socket($sendSock, PF_INET, SOCK_DGRAM, getprotobyname('udp'))   
    || die "socket: $!";
setsockopt($sendSock, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))   
    || die "setsockopt: $!";
# create socket with ephemeral port for sending $port = 0
bind($sendSock, sockaddr_in(0, INADDR_ANY))  || die "bind: $!"; 

# create socket for multicast receive
my $recvSock;
my $mcastIP = '239.255.1.2';
my $mcastPort = 9999;

socket($recvSock, PF_INET, SOCK_DGRAM, getprotobyname('udp'))   
   || die "socket: $!";
setsockopt($recvSock, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))   
   || die "setsockopt: $!";

# join to specific port and IPV4 address to select mcast interface
my $imr_multicast = inet_aton($mcastIP);
my $imr_interface = INADDR_ANY;
my $ip_mreq = pack_ip_mreq($imr_multicast, $imr_interface);
my $ip = getprotobyname( 'ip' );

setsockopt($recvSock, $ip, IP_ADD_MEMBERSHIP, $ip_mreq)     
    || die "setsockopt IP_ADD_MEMBERSHIP failed: $!";

# bind to multicast address to prevent reception of unicast packets on this port
bind($recvSock, sockaddr_in($mcastPort, inet_aton($mcastIP)))  || die "bind: $!"; 

# disable multicast loopback so I don't get my own packets
# only do this if you're running instances on seperate machines otherwise you won't
# get any packets
# setsockopt( $recvSock, $ip, IP_MULTICAST_LOOP, pack( 'C', $loop ) ) 
  #  || die( "setsockopt IP_MULTICAST_LOOP failed: $!" );

# fork sender and receiver
my $pid = fork();
if ( $pid == 0) {
    mrecv();
} else {
    msend();
}    

sub msend {
    close($recvSock);
    while (1) {
        my $datastring = `date`; chomp($datastring);
        $datastring = "$datastring :: $pid\n";
        my $bytes = send($sendSock, $datastring, 0, 
                         sockaddr_in($mcastPort, inet_aton($mcastIP)));
        if (!defined($bytes)) { 
            print("$!\n"); 
        } else { 
            print("sent $bytes bytes\n"); 
        }
        sleep(2);
    }
}

# just loop forever listening for packets
sub mrecv {
    close($sendSock);
    while (1) {
        my $datastring = '';
        my $hispaddr = recv($recvSock, $datastring, 64, 0); # blocking recv
        if (!defined($hispaddr)) {
            print("recv failed: $!\n");
            next;
        }
        print "$datastring";
    }
} 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!