17.10. Writing Bidirectional ClientsProblemYou want set up a fully interactive client so you can type a line, get the answer, type a line, get the answer, etc., somewhat like telnet . SolutionOnce you've connected, fork off a duplicate process. One twin only reads your input and passes it on to the server, and the other only reads the server's output and sends it to your own output. Discussion
In a client-server relationship, it is difficult to know whose turn it is to talk. Single-threaded solutions involving the four-argument version of
Once you've connected to the service you'd like to chat with, call The code is in Example 17.4 . Example 17.4: biclient#!/usr/bin/perl -w # biclient - bidirectional forking client use strict; use IO::Socket; my ($host, $port, $kidpid, $handle, $line); unless (@ARGV == 2) { die "usage: $0 host port" } ($host, $port) = @ARGV; # 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()); if ($kidpid) { # parent copies the socket to standard output while (defined ($line = <$handle>)) { print STDOUT $line; } kill("TERM" => $kidpid); # send SIGTERM to child } else { # child copies standard input to the socket while (defined ($line = <STDIN>)) { print $handle $line; } } exit; To accomplish the same thing using just one process is remarkably more difficult. It's easier to code two processes, each doing a single task, than it is to code one process to do two different tasks. Take advantage of multitasking by splitting your program into multiple threads of control, and some of your bewildering problems will become much easier.
The
If the remote server sends data a byte at time and you need that data immediately without waiting for a newline (which may never arrive), you may wish to replace the my $byte; while (sysread($handle, $byte, 1) == 1) { print STDOUT $byte; } Making a system call for each byte you want to read is not very efficient (to put it mildly), but it is the simplest to explain and works reasonably well. See Also
The
Copyright © 2001 O'Reilly & Associates. All rights reserved. |
|