Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



17.10. Writing Bidirectional Clients


17.10.1. Problem




You 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.

17.10.2. Solution


Once you've connected, fork off a duplicate process. One twin reads
only your input and passes it on to the server, and the other reads
only the server's output and sends it to your own output.

17.10.3. 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 select are hard to write and maintain.
But there's no reason to ignore multitasking solutions. The
fork function dramatically simplifies this
problem.

Once you've connected to the service you'd like to chat with, call
fork to clone a twin. Each of these two (nearly)
identical processes has a simple job. The parent copies everything
from the socket to standard output, and the child simultaneously
copies everything from standard input to the socket.

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 kill function in the parent's
if block is there to send a signal to the child
(currently running in the else block) as soon as
the remote server has closed its end of the connection. The
kill at the end of the parent's block is there to
eliminate the child process as soon as the server on the other end
goes away.

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 while loop in the
parent with the following:

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.

17.10.4. See Also


The sysread and fork functions
in Chapter 29 of Programming Perl and in
perlfunc(1); the documentation for the standard
IO::Socket module;
Recipe 16.5; Recipe 16.10; Recipe 17.11



17.9. Closing a Socket After Forking17.11. Forking Servers




Copyright © 2003 O'Reilly & Associates. All rights reserved.

/ 875