shadowoflinux has asked for the wisdom of the Perl Monks concerning the following question:

Hey,
i've been writing a very simple talk program that connects to a remote computer, and sends it a message. Currently it is in 2 parts, a script that is run to recieve messages, and a script that is run to send them.
Send.p code
#!/usr/bin/perl # use strict; use warnings; use IO::Socket; my $sock = new IO::Socket::INET ( PeerAddr => 'dan', PeerPort => '7070', Proto => 'tcp', ); die "Could not create socket: $!\n" unless $sock; print "What would you like to say: "; my $msg = <STDIN>; print $sock "$msg\n"; close $sock;

recieve.p code

#!/usr/bin/perl # use strict; use warnings; use IO::Socket; my $sock = new IO::Socket::INET ( LocalHost => 'dan', LocalPort => '7070', Proto => 'tcp', Listen => 1, Reuse => 1, ); die "Could not create socket: $!\n" unless $sock; my $new_sock = $sock->accept(); while(<$new_sock>) { print $_; } close $sock;

how could i modify those scripts so that a) they dont close after 1 message and b) so that the same script can be used to send and recieve?
thanks

EDIT: is there a way of setting up the scripts so they can send and recieve at the same time, without using a server, so they connect directly to each other, almost like a 2-way radio?

Morning!

Replies are listed 'Best First'.
Re: Perl Sockets Problem
by zentara (Cardinal) on Jun 01, 2006 at 16:10 UTC
    You are looking for a Chat server-client pair. There are tons of examples around. First step, in your client, you need to remove the
    close $sock;
    line.

    Here is a simple server-client pair. If you want them in a single script, just put them in subs, and run them depending on a commandline argument like 's' for server, or 'c' for client.

    #server #!/usr/bin/perl use IO::Socket; use IO::Select; my @sockets; my $machine_addr = '192.168.0.9'; $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();

    #client #!/usr/bin/perl -w use strict; use IO::Socket; my ( $host, $port, $kidpid, $handle, $line ); ( $host, $port ) = ('192.168.0.9',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"; } }

    I'm not really a human, but I play one on earth. flash japh
Re: Perl Sockets Problem
by ikegami (Patriarch) on Jun 01, 2006 at 17:53 UTC
    Not an answer, but don't mix buffered and unbuffered IO. syswrite and sysread should be used with sockets rather than print and <>.
Re: Perl Sockets Problem
by dsheroh (Monsignor) on Jun 01, 2006 at 16:11 UTC
    For a), changing the last few lines of the sending script to:
    while (my $msg = <STDIN>) { print $sock "$msg\n"; } close $sock;
    should do the trick. The receiver is already set up to keep listening until the socket gives it an EOF.

    For b), I suppose a command-line switch to tell it whether to start in client (sender) or server (receiver) mode, then use the appropriate set of args to IO::Socket->new and corresponding while loop based on that.

A reply falls below the community's threshold of quality. You may see it by logging in.