Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Can a socket listen for multiple hosts?

by steve (Deacon)
on Jan 22, 2010 at 20:11 UTC ( [id://819046]=note: print w/replies, xml ) Need Help??


in reply to Can a socket listen for multiple hosts?

There are a lot of modules that can help in this process, and it might help to take a look at the documentation for a few on CPAN to see how you can use them for your particular application. For example, Net::Server and possibly Net::Server::Simple are easy to use and may work for what you are trying to do.
  • Comment on Re: Can a socket listen for multiple hosts?

Replies are listed 'Best First'.
Re^2: Can a socket listen for multiple hosts? -- UPDATE
by sierpinski (Chaplain) on Jan 22, 2010 at 20:53 UTC
    Thanks for the responses. I ended up using IO::Select, and got it working. Posting the code here for posterity/review. Thanks!
    #!/usr/bin/perl use IO::Socket; use IO::Select; my $socket =new IO::Socket::INET->new ( LocalHost => "<ipaddress>", LocalPort => '<port>', Proto => 'tcp', Listen => 1, Reuse => 1, ); die("Couldn't create socket! $!\n") unless $socket; my $select = new IO::Select($socket); while(@ready = $select->can_read) { foreach $fh (@ready) { if($fh == $socket) { $new = $socket->accept; $select->add($new); my $host= $new->peerhost; print "[Accepting connection from $host]\n"; } else { my $line = <$fh>; $line =~ s/\s+$//; if($line =~/^quit$/i) { my $host = $fh->peerhost; $select->remove($fh); $fh->close; print "[Connection from $host terminat +ed\n"; } else { print $fh->peerhost, " said '$line'\n" +; print $fh "You said: '$line'\n"; } } } }
    Thanks for all the help! With multiple servers sending at the same time, it keeps track (using peerhost) which host sends the message, and of course the message contents.
    /\ Sierpinski

      Don't use buffered IO (e.g. read, readline aka <>) with select. You could get into a situation where data is waiting in Perl's buffer, and select wouldn't know anything about it.

      Don't use IO that blocks after it reads all that's available to be read (e.g. read, readline aka <>) with select. It defies the purpose of using select.

      You don't handle EOF, so you could end up having a handle that's permanently ready to read.

      Fixed:

      #!/usr/bin/perl use strict; use warnings; use IO::Socket::INET qw( ); use IO::Select qw( ); sub process_msg { my ($client, $msg) = @_; chomp $msg; my $host = $client->peerhost; print "$host said '$msg'\n"; return lc($msg) eq 'quit; } my $server = IO::Socket::INET->new( ... ) or die("Couldn't create server socket: $!\n"); my $select = IO::Select->new($server); my %bufs; while (my @ready = $select->can_read) { for my $fh (@ready) { if ($fh == $server) { my $client = $server->accept; $select->add($client); $bufs{fileno($client)} = ''; my $host = $client->peerhost; print "[Accepted connection from $host]\n"; } else { our $buf; local *buf = \$bufs{fileno($fh)}; my $rv = sysread($fh, $buf, 64*1024, length($buf)); if (!$rv) { my $host = $fh->peerhost; if (defined($rv)) { print "[Connection from $host terminated]\n"; } else { print "[Error reading from host $host: $!]\n"; } process_msg($fh, $buf) if length($buf); delete $bufs{fileno($fh)}; $sel->remove($fh); next; } while ($buf =~ s/\G(.*\n)//g) { if (!process_msg($fh, "$1")) { my $host = $fh->peerhost; print "[Connection from $host terminated]\n"; delete $bufs{fileno($fh)}; $sel->remove($fh); last; } } } } }
        Thanks for the response! I knew it was a good idea to post my code here. I'm using the updated version, and it is working. I just need to go through and make sure I understand what the differences are... definitely a learning experience.

        Thanks again!
        /\ Sierpinski
        EDIT: Not sure what I was thinking, Monday morning I guess. I just replaced the \n chars with something else, searched for that after the transmission, then replaced them with \n's again afterward. It works great.

        Ikegami, thanks again for the response.
        I've been trying to decode this, and I think it mostly makes sense to me, but I need to be able to send multi-line messages (ie \n chars embedded) and want to terminate the sending connection with a specific character string. In other words, I'll have a datagram that looks something like this:

        &&&hostname|blue*** (the start/end chars can be anything)
        &&&ipaddress|1.2.3.4***
        &&&kernelrev|123456-78***
        &&&metastat|line1\nline2\nline3\n***

        So I basically will be sending all types of data, but I want it to start paying attention when &&& is read, and read until ***, storing the contents in a var. (Probably will end up using a hash, if it matters)

        I thought I had a good grip on how exactly that code works, but when I change what I thought I should change, it doesn't work as I expected. Any thoughts to send me in the right direction?

        Much appreciated!
        /\ Sierpinski

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://819046]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-18 18:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found