gnu@perl has asked for the wisdom of the Perl Monks concerning the following question:

I have a simple program that accepts a connection on the network then opens a named pipe to read data from and send that data to the connectet client.

For the most part it works fine. I have one problem though. I don't know how to tell, in a loop, if the client is still connected. This causes a problem when a client disconnects. The next read of the pipe is still pending and the state of the loop thinks the client is still there so it prints the next data it receives to the socket.

On the next iteration I again check to make sure the client is there and if it isn't I go back into accept(). With this model, I lose 1 loops worth of data each time a clients disconnects.

Any Ideas? I'm stumped. Anyway, here is the code and thanks in advance:

#!/usr/bin/perl -w use strict; use IO::Select; use IO::Socket; my $pipefile = shift || "./genpipe"; my $serverPort = shift || 4509; syswrite(STDOUT,"Before listenSocket\n"); my $listenSocket = IO::Socket::INET->new(LocalPort => $serverPort, Listen => 50, Proto => 'tcp', Reuse => 1, timeout => 60*60, ); die "Cannot set up listening socket!\n" unless $listenSocket; while (1) { my $incoming = $listenSocket->accept(); $incoming->autoflush(1); syswrite(STDOUT,"ACCPETED -> $incoming\n"); while ($incoming->connected()) { open(PIPE,"<$pipefile") or die "Cannot open pipe $pipefile. $ +!\n"; if (! $incoming->connected() ) # The above line will always be the same # as the initial check before the loop, so # I never get to the code block just below, # and I lose the data on this iteration. { close(PIPE); syswrite(STDOUT,"EXECUTING 'last' STATEMENT!\n"); last; } syswrite(STDOUT,"OPENED PIPE\n"); syswrite(STDOUT,"** just before reading pipe\n"); syswrite(STDOUT,"just before write to channel\n"); map {syswrite($incoming,$_)} (<PIPE>); syswrite(STDOUT,"just after write to channel\n"); close(PIPE); } }

Replies are listed 'Best First'.
Re: Simple TCP Server to output data
by pg (Canon) on Mar 17, 2003 at 23:08 UTC
    It is not part of the TCP standard, to check whether the peer is still alive, or whether the connection is still there. The TCP conncections are only maintained "locally".

    connected() can not be used to check the availability of peer, or the status of connection.

    However for Perl socket programs, when the peer closes the connection, you would reach eof of the socket, just as a normal file does.

    This demo shows how the socket reaches eof, when yahoo closes the connection after the transmission is done:
    use strict; use IO::Socket; my $yahoo = IO::Socket::INET->new(Proto => "tcp", PeerPort => 80, PeerAddr => "www.yahoo.com", Timeout => 2000) || die "failed to connect\n"; my $req = "GET / HTTP/1.1\r\nHost: www.yahoo.com\r\n\r\n"; print $yahoo $req; my $count = 0; while (<$yahoo>) { print "packet count = ", ++ $count, ", and first 20 chars of the p +acket = ", substr($_, 0, 20), "\n"; }
      Thanks for your help, but what you have shown is a client, I am writing a server. The problem I have is knowing when the client has disconnected from me.

      I am thinking that the only real way for me to know is to write a null to the client before I do the actual write, if that works the client is probably still there, otherwise it has disconnected.

Re: Simple TCP Server to output data
by gnu@perl (Pilgrim) on Mar 20, 2003 at 15:29 UTC
    Ok, first I would like to say thanks to everyone for the information that was offered. Next, I would like to post the finished code. I had to modify it quite a bit. I now have a parent process that spawns 2 child processes.

    Child process 1 is the reader that reads the named pipe and writes the output to a spool file. This keeps the input on the pipe from blocking and the program writing to it can just keep on going. Also, it allows me to have a cache of activity in the event a client is not connected to receive the data.

    Child process 2 is the creation of the listen socket and accept of the incoming connection. I only wanted one client connected at a time so I close the listen socket once one has connected. There is a commented block on how I handled the detection of a client side disconnection (Thanks Drysart).

    I used flock to control access to the spool file so that no data is lost in the copy of the spool file to a temp file to write to the client socket.

    Anyway, here is the code. I hope it can help out others. I sure learned quite a bit while doing it. If anyone has questions on why or how I did something please msg me.
    code.....