Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

TCP/IP

by Jason0x21 (Initiate)
on Apr 05, 2000 at 04:22 UTC ( [id://6906]=perlquestion: print w/replies, xml ) Need Help??

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

I'm working on a server daemon program that will provide a running "tail" of a log file to clients connected with "telnet". To start with, I used the forking server shown on pages 350-351 in Chapter 6 of the
    Programming Perl
book. I modified the spawn call so that the code looks like this...
    spawn sub {
        my($nodie) = 1;
        my(@tail)  = ();
        my($err)   = 0;
        print "Hello there, $name, it's now ", scalar localtime, $EOL;
        open(REQLOG,$ReqLog) || confess "can't open $ReqLog: $!";
        while(<REQLOG>) {
            push(@tail,$_);
            if($#tail>10) {  shift(@tail);  }
            }
        foreach(@tail) {  print $_,"\r";  }
        while($nodie) {
            while(<REQLOG>) {
                if(! print $_,"\r") {
                    confess "can't print to socket: $!";
                    $nodie = 0;  last;
                    }
                    }
                }
            sleep(5);  seek(REQLOG,0,1);
            }
        };
    }
The "tailing" procedure works just fine, the problem happens when I disconnect from the client side. The forked server sending data to the client doesn't exit. I don't get any messages. Is there a signal I'm supposed to be looking for here? Thanks in advance.

Replies are listed 'Best First'.
Re: TCP/IP
by mikfire (Deacon) on Apr 05, 2000 at 07:29 UTC
    If I have analyzed this correctly - and it took some time to figure that out - your problem is in the block
    while($nodie) { while(<LOGREQ>) { if(! print $_,"\r") { confess "can't print to socket: $!"; $nodie = 0; last; } } }
    Instead of the last, you need to exit. The example you reference is, according to my Camel, using an exec() which performs much magic ( which I can explain offline if you wish ). The end result, though, is that the spawned child exits when the command ( fortune ) finishes.

    If I have figured this out correctly, your last only drops you out of the innermost loop - the while(<LOGREQ>) loop. Perl transfers control to the next outermost block - which is the while ($nodie) in this case. $nodie as always 1.

    So your code is constantly trying to write to a closed socket, failing, it executes the last and then this loop all over again.

    If you change the last to an exit, the forked process will die on error, not get its poor little head caught in an infinite loop.

    Of course, I could be wrong. I am still not certain on a few aspects of this code.

    Mik
    Mik Firestone ( perlus bigotus maximus )

Re: TCP/IP
by plaid (Chaplain) on Apr 05, 2000 at 06:28 UTC
    This is just a preliminary response, I'll look into it more if this doesn't work. It looks like the problem is that your anonymous sub needs to exit at the end, not just return as yours is. The example in the book has the spawn subroutine called with an anonymous sub that execs at the end, and an exec exits at the end, never returning control to the program. Anyways, I haven't looked at the code for the spawn sub yet, but I'll do that and see if anything else that you might need to do stands out.
Re: TCP/IP
by Jason0x21 (Initiate) on Apr 05, 2000 at 19:13 UTC
    I probably should have done this at the outset, but the full text of the code is available at http://www.wxdu.duke.edu/~jason/request-server.txt, which should clear up how it's supposed to work, I think. I originally posted a snippet of code calling the fuction spawn with an anonymous subroutine defined as the argument to spawn. I know last only does the inner loop, that's why I set $nodie to 0 before I call last. Thanks again!
      Yeah, I was right. I was a moron. I totally missed the $nodie = 0 line. mea culpa.

      I will look at it more tonight when I can play harder and try again. Unless some other member of this august assembly provides a better clue.

      mik

Re: TCP/IP
by Jason0x21 (Initiate) on Apr 06, 2000 at 00:42 UTC
    I'm running this on a Linux box (redhat 6.1), and what appears to happen is the SIGPIPE doesn't happen until a two updates have been done to the file I'm "tailing". I'd guess it was some sort of flushing problem, but the updates get sent to the live telnet session in a timely manner, and get sent to the file in question appropriately as well. So it looks like the problem isn't a perl problem at all, but some sort of funky buffering problem. Thanks!
Re: TCP/IP
by mikfire (Deacon) on Apr 06, 2000 at 00:55 UTC
    I am beginning to see some... unanticipated behaviour from this. With the way your loop is set up, the forked server will not notice the pipe is broken until the file has changed.

    For example,

    server.pl 59683: server started on port 8870 at Wed Apr 5 16:28:55 20 +00 server.pl 59683: connection from localhost [ 127.0.0.1 ] at port 2110 +at Wed Apr 5 16:29:16 2000 server.pl 59683: begat 59693 at Wed Apr 5 16:29:16 2000
    I broke that connection at 16:29:25. It is now 16:32:08 and I have not seeen the reap message. If cause the file I am monitoring to be updated ( approx 16:33:09 ), the reaping code is fired and I see:
    broken pipe at server.pl line 50 main::SELFREAP('PIPE') called at server.pl line 82 main::__ANON__() called at server.pl line 113 main::spawn('CODE(0x804e054)') called at server.pl line 89 server.pl 59683: reaped 59693 with exit 65280 at Wed Apr 5 16:34:02 +2000
    If I add this:
    if ( eof(<STDIN> ) { confess "No more socket?"; $nodie = 0; last; }
    after your call to seek, the spawned server dies when I would expect.

    If I am still smoking crack, I will give up on this problem a apologize again for wasting everybody's time.

    Mik
    Mik Firestone ( perlus bigotus maximus )

RE: TCP/IP
by Anonymous Monk on Apr 05, 2000 at 23:38 UTC
    When I run your code on a linux box, the child process catches a SIGPIPE after telnet exits *and* it tries to subsequently write to the socket:
    broken pipe at ././test-server2 line 50 main::SELFREAP('PIPE') called at ././test-server2 line 85 main::__ANON__() called at ././test-server2 line 121 main::spawn('CODE(0x80cdb14)') called at ././test-server2 line + 96 broken pipe at ././test-server2 line 50 main::SELFREAP('PIPE') called at ././test-server2 line 0 ././test-server2 9192: reaped 9761 with exit 7424 at Wed Apr 5 12:23: +32 2000
    What platform are you running on. Trying to write to a closed socket should definitely generate a SIGPIPE.
Re: TCP/IP
by turnstep (Parson) on Apr 05, 2000 at 05:09 UTC
    Previous post erased - nothing to see here, move along... (btrott was right, I was wrong:)
      I don't have Programming Perl, but what it looked like the original poster's code was doing was *calling* the spawn sub, not defining it; calling it with a code reference.

      Is that correct? If so, I doubt the sub ref would have to contain a fork, as the actual spawn sub contains the fork.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://6906]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-03-29 15:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found