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
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.
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 ) | [reply] [Watch: Dir/Any] [d/l] |
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. | [reply] [Watch: Dir/Any] |
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! | [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
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! | [reply] [Watch: Dir/Any] |
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 ) | [reply] [Watch: Dir/Any] [d/l] [select] |
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. | [reply] [Watch: Dir/Any] [d/l] |
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:) | [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|