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

Hi, I am writing a server, that accepts a connection from a client, forks, and handles client's requests in the child process. The parent is free to accept more connections.
sub ServerRun { my ($server)=@_; my ($client); #wait for client connections while ($client = $server->accept()) { $client->autoflush(1); my $pid = fork; if ($pid == 0) { my $clsock=HandleClient($client); close $clsock; exit 0; } } } sub HandleClient { # this just recieves system commands # to be executed and returns output to client # fn. returns the $client socket }
The problem is threads are somehow interfiering with each other. For e.g. one client wants 'system ("ll")'.. the output is not sent back until another client has connected and sent it's request. Also: when the 'close $clsock;' statment is executed the client is not dissconnected until another client connects or sends a request in HandleClient function. Any ideas why this is happening? It seems to me a thread is somehow paused, until some other thread does something else. I thought threads should run (virtually) paralell.

Replies are listed 'Best First'.
Re: Multi threaded server [fork]
by zby (Vicar) on Aug 06, 2003 at 09:37 UTC
    I'd like to know how did you check that there is that interference. Perhaps it was just output buffering or some other coincidence (to have non buffered output you need to add $| = 1 to your scripts). I think it is not possible for Unix processes to directly interfere one with another (not using some IPC technique). Beside that you are not using threads - you might confuse people when you talk about interfering threads and mean interfering child processes.
      oops, by threads I ment chind processes. I tested it using multiple "telnet <host> <server port>"s. I used one telnet for a couple of 'system's and when I started another telnet and typed a command it did not send me reply until i typed a command in the 1st telnet. Then the 1st telnet command "waited" until i typed a command in the 2nd telnet. Also: when I typed a command, that indicates to the server it should close the connection it closed it but not until I typed a command in the other telnet.
Re: Multi threaded server [fork]
by SyN/AcK (Scribe) on Aug 06, 2003 at 15:06 UTC

    This seems like strange behavior to me. I think what you need to do is call waitpid($child, 0); This should cause the parent process to continue to work. I think this would have been better done with threads, however, but that's just my opinion.

    Here's an example of forking that I found on the net:

    #!/usr/bin/perl use strict; use warnings; use POSIX ':sys_wait_h'; if (fork) { # parent print "[Parent]\n"; until (waitpid(-1, &WNOHANG)) { print "waiting...\n"; sleep 1; } print "[Parent End]\n"; } else { # child print "[Child]\n"; sleep 10; my $i = 1; print "[Child End]\n"; }
    I think you're definitely going to need to use the signals.

      This variant would pause the parent process until the child finished its work, which is just the thing I am trying to avoid here (PS: parent always worked OK, problems arose when many clients connected - they only interfiered with each other, not with the parent). Anyway, I guess i'll have to do some reading about real threads and see what are the differences betewen threads and child processes.
Re: Multi threaded server [fork]
by chromatic (Archbishop) on Aug 06, 2003 at 18:01 UTC

    Semantic quibble: these aren't threads, they're processes. There's a big difference with regard to synchronicity and shared resources.

    That said, what happens if you close the connection in the parent after you've forked off a child? If one process still has a connection open to the client, how does the client know it's finished reading? You might be able to get away with this:

    while (my $client = $server->accept()) { # as normal }

    This is untested, though, and I haven't looked in a networking book to be sure.

      Unfortunatly i just got some higer priority work, so i'll have to stick to 'one client at a time' server for some time. To answer your questions: close conn. in parent: This would probbably work fine, since everything i do in the parent works as expected (have no time to test, though). how do server and client communicate: when server accepts the connection it forks off a child server, which, in a while loop, recieves one line of command and sends back the output. Last line of output is 'END\012\015', which indicates to the client stop reading. The client may then send a new command or 'SessionQuit\012\015', in which case the server closes the client connection and function returns.