Solved

Perl and Networking:

Posted on 2002-05-25
10
851 Views
Last Modified: 2012-06-27
Perl and Networking:
It is easy to connect one computer to another using Perl & TCP, if at least one computer knows the IP address of the other. But, is there a way to send a message to all computers on a network on a certain port? A sort of "Hello I'm here!" message? TCP? UDP? Something else?

I'd like to make some programs that can wander (mobile agents) but they won't know what machines are up and running before hand.  They need the ability to send a message out on a port that identifies themselves to the other bots. I also don't want to have to have a list of IP's to try. This should be automatic.

Any ideas?

0
Comment
Question by:jgore
  • 6
  • 4
10 Comments
 
LVL 51

Expert Comment

by:ahoffmann
ID: 7036829
there are a couple of modules for this purpose, have a look at http://www.cpan.org/
Which module you want, depends on your requirements.
0
 

Author Comment

by:jgore
ID: 7038408
I know now that UDP is the way to go for what I want.
It will let you BROADCAST to many machines at once.
I have yet to see an example of Broadcasting but I will
post it if I find it. Or, one of you could post it as the
answer to this question. Most of the examples I've seen
have to do with sending to one particular machine :-(
 

Here is a little UDP Receiver:
-------------------- snip  --------------------------

#!\perl\bin\perl.exe
# ^^^  Watch that Shabang line!

# udpqotd - UDP message server
use strict;
use IO::Socket;
my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO);
$MAXLEN = 1024;
$PORTNO = 5151;


  $sock = IO::Socket::INET->new(LocalPort => $PORTNO, Proto => 'udp')
      or die "socket: $@";
   
   print "Awaiting UDP messages on port $PORTNO\n";

   $oldmsg = "This is the starting message.";

while ($sock->recv($newmsg, $MAXLEN))
{
    my($port, $ipaddr) = sockaddr_in($sock->peername);
    $hishost = gethostbyaddr($ipaddr, AF_INET);
    print "Client $hishost said ``$newmsg''\n";
    $sock->send($oldmsg);
    $oldmsg = "[$hishost] $newmsg";
}
die "recv: $!";






0
 

Author Comment

by:jgore
ID: 7040734
Here is some code I made, gathered from many sources.
It works, and will let you broadcast UDP messages.
Doesn't look like anyone will answer this so I just
post it myself. If anyone has anything intelligent to say about the code or something to add to it I'll give them
the 100 points just to get rid of it.

-------------------------- snip -----------------

#!\perl\bin\perl.exe

use strict;
use IO::Socket;
use IO::Select;

my($SockUDP, $SelectUDP, $MaxLength, $PortUDP);


$MaxLength = 1024;            # Max Length of any Message
$PortUDP = 7171;              # Port Number


# Open a socket on specified port using UDP
$SockUDP = IO::Socket::INET->new(LocalPort => $PortUDP, Proto => 'udp') or die "socket failure: $@";
$SelectUDP = IO::Select->new($SockUDP) || die "select failure: $!";


# ========= Test - broadcast and receive
my $i;
for ($i=1; $i<10; $i++)
{
&ReceiveMessages("10");
&BroadcastMessage("Hello! I'm here!!! >>>Broadcast Message<<< \n");
}


close $SockUDP;

print "\n\nDone Testing UDP\n\n";

# ============================ Receive Messages ========================
sub ReceiveMessages                        # Receive from ALL machines
{
  my $TimeLimit = shift @_;
  my ($buff,$remote,$rport,$raddr,$rhost);

  print "Awaiting UDP messages on port $PortUDP\n";

  my $TimeStart = time;
 
  while($SelectUDP->can_read(5))
  {
   if ( time()-$TimeStart > $TimeLimit ) {last; };   # End if over time limit
   
   $remote = $SockUDP->recv($buff,$MaxLength,0);
   ($rport,$raddr) = sockaddr_in($remote);
   $rhost = gethostbyaddr($raddr,AF_INET);

   print "$rhost:$rport said: $buff\n";
  }

}
# ============================ Send Message ========================
sub SendMessage                              # Send to ONE machine
{
my ($message,$rhost) = @_;                   # What, Who

$SockUDP->send($message,0,$rhost);

}
# ============================ Broadcast Message ===================
sub BroadcastMessage                         # Send to ALL machines
{
   my $message = shift @_;

   my $bcast = sockaddr_in($PortUDP,inet_aton("255.255.255.255"));

   # setup and broadcast
   $SockUDP->sockopt(SO_BROADCAST,1);
   $SockUDP->autoflush(1);
   $SockUDP->send($message,0,$bcast);

}
# ============================ END SOURCE ========================
0
 
LVL 51

Expert Comment

by:ahoffmann
ID: 7041209
'cause I'm not a perl-socket-programmer-expert, I leave out comments about this.
But: are you shure you want to broadcast the hole internet (255.255.255.255)? This would produce at least a huge amount of ICMP messages returned by sevaral involved routers.
And in you unused sub SendMessage I'd swap the What and Who parameter.
0
 

Author Comment

by:jgore
ID: 7043349
ahoffmann:
Your correct in that you wouldn't want to use UDP broadcast
on the internet. I think its main use is for LAN (local
area network). LAN's use IP numbers that are incompatible
with the internet (like  192.168.1.1). They are considered
private addresses. I'm trying to write some Mobile Agents
so UDP is perfect for letting them find each other on my
LAN.
Although, it might be really really fun to use the above
program on a machine tied to the internet and broadcast a
message on all available ports just to see if you get an
answer! LOL! I'm not sure it would work at all...or that
you'd want it to!

Hmmm...I looked at my code and found the SendMessage
routine to be OK (I tested it also.)
Just put:

my $rhost = sockaddr_in($PortUDP,inet_aton("192.168.1.1"));
&SendMessage("Hello!  <<< Private Message >>>",$rhost);

and it seems to work. The "What" means what are you
sending  and the "Who" is who are you sending to. In the
above case we are sending a "Hello" message to the machine
at address 192.168.1.1.

The ReceiveMessage had some unnecessary code for the
timer. That is taken care of for us.
The ReceiveMessage routine should read:

# ============================ Receive Messages ========================
sub ReceiveMessages                        # Receive from ALL machines
{
  my $TimeLimit = shift @_;
  my ($buff,$remote,$rport,$raddr,$rhost);

  print "Awaiting UDP messages on port $PortUDP\n";

  while($SelectUDP->can_read($TimeLimit))
  {
   $remote = $SockUDP->recv($buff,$MaxLength,0);
   ($rport,$raddr) = sockaddr_in($remote);
   $rhost = gethostbyaddr($raddr,AF_INET);
   print "$rhost:$rport said: $buff\n";
  }

}
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 51

Accepted Solution

by:
ahoffmann earned 100 total points
ID: 7043743
didn't say that SendMessage won't work, just said that it might be better to have "who" as first patameter ('cause "what" is a whitespace and/or comma delimited list)

Mobile agent on any system connected to the internet (pc, phone, fridge, ...), and each broadcasting ...
Let's have fun, ROFLOL

Anyway, I'm personaly interested in this kind of agents, lets continue ..
0
 

Author Comment

by:jgore
ID: 7044018
Here is a OOP version of above.  I wrote this to make it
easier to use. And this way you can be using several differnt ports at once. The only thing I haven't really
figured out is how to have the darn thing listening all the
time and still be able to do other stuff. Using Objects
has confused me more about this.

Warning: I'm new to OOP (Objects,Classes).
Save the following as "AgentCom.pm"
-------------------------- snip -------------------
package AgentCom;

use strict;
use IO::Socket;
use IO::Select;

my $self;

# ============================ New  ========================
 sub new {                             # constructor

        my $proto = shift;
        my $class = ref($proto) || $proto;
        my $self  = {};
       
        $self->{SockUDP} = undef;
        $self->{PortUDP} = undef;
        $self->{MaxLengthUDP} = undef;
        $self->{SelectUDP} = undef;
       
        bless ($self, $class);
        return $self;
    }

# ============================ Init UDP ========================
sub initUDP                             # Only Need Port Number, Message length optional
{
my $self = shift;
$self->{PortUDP} = shift;

$self->{MaxLengthUDP} = shift;                                  # Max message length
if (!$self->{MaxLengthUDP}) { $self->{MaxLengthUDP} = 1024; }   # Default

# Make new UDP sock and select
$self->{SockUDP} = IO::Socket::INET->new(LocalPort => $self->{PortUDP}, Proto => 'udp') or die "socket failure: $@";
$self->{SelectUDP} = IO::Select->new($self->{SockUDP}) || die "select failure: $!";
}
# ============================ DESTROY ========================
sub DESTROY
{
my $self = shift;

# Close UDP socket and select if we have them
if (defined $self->{SelectUDP}) { close $self->{SelectUDP}; }
if (defined $self->{SockUDP})   { close $self->{SockUDP}; }

}
# ============================ Receive UDP Messages ========================
sub ReceiveUDP                                 # Receive from ALL machines
{
  my ($self, $TimeLimit) = @_;

  my ($message,$remote,$rport,$raddr,$rhost,@messagelist);
# print "Awaiting UDP messages on port $self->{PortUDP}. Time limit:$TimeLimit\n";

  while($self->{SelectUDP}->can_read($TimeLimit))
  {
   $remote = $self->{SockUDP}->recv($message,$self->{MaxLengthUDP},0);
   ($rport,$raddr) = sockaddr_in($remote);
   $rhost = gethostbyaddr($raddr,AF_INET);

   push(@messagelist,"$rhost:$rport said: $message");
#    print "$rhost:$rport said: $message\n";
  }

return @messagelist;
}
# ============================ Send UDP Message ========================
sub SendUDP                                 # Send to ONE machine
{
   my ($self,$rhost,$message) = @_;               # Bot to send to, Message to send
   $self->{SockUDP}->send($message,0,$rhost);
}
# ============================ Broadcast UDP Message ===================
sub BroadcastUDP                            # Send to ALL machines
{
   my ($self,$message) = @_;
 
   my $bcast = sockaddr_in($self->{PortUDP},inet_aton("255.255.255.255"));
   $self->{SockUDP}->sockopt(SO_BROADCAST,1);       # setup and broadcast
   $self->{SockUDP}->autoflush(1);
   $self->{SockUDP}->send($message,0,$bcast);

}
# ============================ END SOURCE ========================
1;
----------- end "AgentCom.pm" --------------



Save the following as any name. I call it "Bot_One.pl".
---------------------- snip ----------------

#!\perl\bin\perl.exe

use strict;
use AgentCom;

my $BotCom = AgentCom->new();         # Create UDP Communication Object
$BotCom->initUDP("7171",1024);        # Initialize UDP with port and Max message length


# Broadcast a message and then listen for 10 seconds
$BotCom->BroadcastUDP("Anyone there?");    # Send a UDP broadcast on LAN
my @messages = $BotCom->ReceiveUDP(10);    # Get messages from others and self for 10 seconds

# Print any messages. It should show self broadcast
if (@messages) { print "@messages\n"; }
else { print "No messages received :-( \n"; }

----------- end "Bot_One.pl" ---------------------
0
 

Author Comment

by:jgore
ID: 7044053
ahoffmann said:
>'cause "what" is a whitespace and/or comma delimited list

I hadn't thought of sending anything but a scalar.
But I switched them anyway. It would be easier to add things
later that way also.

 
0
 
LVL 51

Expert Comment

by:ahoffmann
ID: 7044140
so the question is closed now,
I'm still interested in mobile code, somehow ...
0
 

Author Comment

by:jgore
ID: 7046453
ahoffmann:

Try:
http://raleigh.pm.org/agents/Its a very small page, but has a few good links to Perl
mobile agents.

Try:
http://tiamat.epn.nu/~spurkis/Agent/
Agent Perl. Very nice.

Also, Penguin is still on Cpan for Perl.

A search for "mobile agents" on any search engine will
give you a headache. Mostly just people talking about them
but doing very little. But there are a few good things out
there.

In any case, good luck!

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now