[ Pobierz całość w formacie PDF ]
.005 release.# Forking serveruse IO::Socket;$SIG{CHLD} = sub {wait ()};$main_sock = new IO::Socket::INET (LocalHost => 'goldengate',LocalPort => 1200,Listen => 5,Proto => 'tcp',Reuse => 1,);die "Socket could not be created.Reason: $!\n" unless ($sock);while ($new_sock = $main_sock->accept()) {$pid = fork();die "Cannot fork: $!" unless defined($pid);if ($pid == 0) {# Child processwhile (defined ($buf = )) {# do something with $buf.print $new_sock "You said: $buf\n";}exit(0); # Child process exits when it is done.} # else 'tis the parent process, which goes back to accept()}close ($main_sock);The fork call results in two identical processes - the parent and child - starting from the statementfollowing the fork.The parent gets a positive return value, the process ID ($pid) of the child process.Bothprocesses check this return value and execute their own logic; the main process goes back to accept, andthe child process reads a line from the socket and echoes it back to the client.Incidentally, the CHLD signal has nothing to do with IPC per se.On Unix, when a child process exits (orterminates abnormally), the system gets rid of the memory, files, and other resources associated with it.But it retains a small amount of information (the exit status if the child was able to execute exit(), or atermination status otherwise), just in case the parent uses wait or waitpid to enquire about this status.Theterminated child process is also known as a zombie process, and it is always a good thing to remove itusing wait; otherwise, the process tables keep filling up with junk.In the preceding code, wait doesn'tblock, because it is called only when we know for sure that a child process has died - the CHLD signalarranges that for us.Be sure to read the online documentation for quirks associated with signals in generaland SIGCHLD in particular.12.3.2 Multiplexing Using selectThe reason we forked off a different process in the preceding section was to avoid blocking during accept,read, or write for fear of missing out on what is happening on the other sockets.We can instead use theselect call, introduced in BSD Unix, that returns control when a socket (any filehandle, in fact) can beread from or written to.This approach allows us to use a single-threaded process - somewhat akin tofiring the receptionist and handling all the incoming calls and conversations ourselves.The interface to the native select call is not very pretty, so we use the IO::Select wrapper module instead.Consideruse IO::Socket;use IO::Select;$sock1 = new IO::Socket (.);$sock2 = new IO::Socket (.);$read_set = new IO::Select;$read_set->add($sock1);$write_set = new IO::Select;$write_set->add($sock1, $sock2);The IO::Select module's new method creates an object representing a collection of filehandles, and addand remove modify this set.The select method (which calls Perl's native select function) accepts three setsof filehandles, or IO::Select objects, which are monitored for readability, writability, and error conditions,respectively.In the preceding snippet of code, we create two such sets - a filehandle can be added to anyor all of these sets if you so wish - and supply them to the select method as follows:($r_ready, $w_ready, $error) =IO::Select->select($read_set, $write_set, $error_set, $timeout);select blocks until an interesting event occurs (one or more filehandles are ready for reading, writing, orreporting an error condition) or the time-out interval has elapsed.At this point, it creates three separatelists of ready filehandles and returns references to them.The time-out is in seconds but can be expressedas a floating-point number to get millisecond resolution.Let us use this information to implement a program that retrieves messages from one or more clients:# Create main socket ($main_socket) as before.#.use IO::Select;$readable_handles = new IO::Select();$readable_handles->add($main_socket);while (1) { #Infinite loop# select() blocks until a socket is ready to be read or written($new_readable) = IO::Select->select($readable_handles,undef, undef, 0);# If it comes here, there is at least one handle# to read from or write to.For the moment, worry only about# the read side.foreach $sock (@$new_readable) {if ($sock == $main_socket) {$new_sock = $sock->accept();# Add it to the list, and go back to select because the# new socket may not be readable yet.$readable_handles->add($new_sock);} else {# It is an ordinary client socket, ready for reading.$buf = ;if ($buf) {#.Do stuff with $buf} else {# Client closed socket.We do the same here, and remove# it from the readable_handles list$readable_handles->remove($sock);close($sock);}}}}We create a listening socket, $main_socket, and configure it to listen on a well-known port.We then addthis socket to a newly created IO::Select collection object [ Pobierz całość w formacie PDF ]