in reply to sockets and such in Perl

It sounds like you are looking for Select, to be able to read multiple sockets "simultaneously". You will find that there are all sorts of "extra details" when dealing with multiple sockets. Things like forking-vs-non-forking servers. If you need to transfer big files, a single headed server running with select, will block while it transfers the big file. So you may need a more complicated "forking server", or even a threaded server.

Another complication is if you want to echo the data to all clients.

Since you havn't shown any code yet, here is a pretty good example of a "non-forking-multi-echoing server using select." The client uses fork. So start the server, and start 3 clients and see how it works. The client dosn't need to fork, you could work out some "protocol" , to indicate when "end-of-send" is reached, and you are switching to receive mode, but you can see it is nicer to use a forked client.

###########SERVER############### #!/usr/bin/perl use IO::Socket; use IO::Select; my @sockets; my $machine_addr = '192.168.0.1'; $main_sock = new IO::Socket::INET(LocalAddr=>$machine_addr, LocalPort=>1200, Proto=>'tcp', Listen=>3, Reuse=>1, ); die "Could not connect: $!" unless $main_sock; print "Starting Server\n"; $readable_handles = new IO::Select(); $readable_handles->add($main_sock); while (1) { ($new_readable) = IO::Select->select($readable_handles, undef, undef +, 0); foreach $sock (@$new_readable) { if ($sock == $main_sock) { $new_sock = $sock->accept(); $readable_handles->add($new_sock); } else { $buf = <$sock>; if ($buf) { print "$buf\n"; my @sockets = $readable_handles->can_write(); #print $sock "You sent $buf\n"; foreach my $sck(@sockets){print $sck "$buf\n";} } else { $readable_handles->remove($sock); close($sock); } } } } print "Terminating Server\n"; close $main_sock; getc(); __END__ ###########CLIENT######################### #!/usr/bin/perl -w use strict; use IO::Socket; my ( $host, $port, $kidpid, $handle, $line ); ( $host, $port ) = ('192.168.0.1',1200); my $name = shift || ''; if($name eq ''){print "What's your name?\n"} chomp ($name = <>); # create a tcp connection to the specified host and port $handle = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => $port ) or die "can't connect to port $port on $host: $!"; $handle->autoflush(1); # so output gets there right away print STDERR "[Connected to $host:$port]\n"; # split the program into two processes, identical twins die "can't fork: $!" unless defined( $kidpid = fork() ); # the if{} block runs only in the parent process if ($kidpid) { # copy the socket to standard output while ( defined( $line = <$handle> ) ) { print STDOUT $line; } kill( "TERM", $kidpid ); # send SIGTERM to child } # the else{} block runs only in the child process else { # copy standard input to the socket while ( defined( $line = <STDIN> ) ) { print $handle "$name->$line"; } } __END__

I'm not really a human, but I play one on earth. flash japh

Replies are listed 'Best First'.
Re^2: sockets and such in Perl
by scotchfx (Sexton) on Jul 03, 2005 at 17:46 UTC
    I did try using Select - in fact I even started by modifying this very example:)

    I had a couple questions in regards to using IO::Select - the first being, how do I select() specifically which client/process I want to speak to, and more importantly, when used in this manner, will the socket/connection be bidirectional (can I both read and write?).

    (see ... ??? comments in code snippet below)

    #this sets up $main_sock to handle multiple connections...??? $readable_handles = new IO::Select(); $readable_handles->add($main_sock); #this returns an array of readable (and writeable) #handles/connections...??? $new_readable) = IO::Select->select($readable_handles, undef, undef+, +0); #So now I can iterate through this array just like I would #for any other, except it is an array of "connections"... foreach $sock (@$new_readable) { #in the case that ($sock == $main_sock) this means that #I need to listen for & add any new connections to the #list of $readable_handles, but why not to $new_readable #as well...??? if ($sock == $main_sock) { $new_sock = $sock->accept(); $readable_handles->add($new_sock); } else { $buf = <$sock>; if ($buf) { #does the line $readable_handles->can_write() mean that #these handles are not bidirectional...??? print "$buf\n"; my @sockets = $readable_handles->can_write(); #print $sock "You sent $buf\n"; foreach my $sck(@sockets){print $sck "$buf\n";} } else { $readable_handles->remove($sock); close($sock); } } }

    This may be a useful implementation, but if you gurus out there could give me the play-by-play on how the code above operates it would help me out tremendously..

    Thanks again... more to come...

      To specifically choose a socket to write to, you could store the "name" and $sock object in some sort of hash, to keep track of them. Then if you want to only write to name "foo" , you can print to $socks{'foo'}{'socket'}. I used an array for simplicity, but you can loop through hash keys too. One thing you will have to watch out for, when printing only to one client, is getting "out -of-sync" with the other clients. Occasionly I have seen situations when looping through the hash-of-sockets, I need to print to all clients, BUT change what I print. Like print some text to socks{'foo'}, but $socks{'bar'} and $socks{'baz'} will just get a newline, or some NO-OP type of tag. It's just something to watch out for.

      If you want a good explanation of how all this works:

      select client server

      After reading the above links, you will see that the modules IO::Socket and IO::Select take care of alot of the details for you.


      I'm not really a human, but I play one on earth. flash japh