Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

How do i detect that the client has disconnected ? (i'm using sysread/write)

by shlomi (Initiate)
on Oct 02, 2001 at 06:04 UTC ( [id://116051]=perlquestion: print w/replies, xml ) Need Help??

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

i tried something like this; it did not work:
my $written = syswrite($sock, $buf, 1024); if (not defined $written) { close_sock($sock); }

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: How do i detect that the client has disconnected ? (i'm using sysread/write)
by pjf (Curate) on Oct 02, 2001 at 10:01 UTC
    You can use getpeername() to reliably tell if your socket is connected or not, if it returns undef, you don't have a connection. This is exactly how IO::Socket handles things.

    The code that you've written should work, although it will close the socket on any connection, not just the connection going away. In particular, if your socket is in non-blocking mode, syswrite can return errors (EAGAIN) if the other side simply isn't ready for more data.

    If you are using non-blocking connections, or multiple connections at once, then the chances are you'll find the built-in function select, or the module IO::Select, very handy for telling when it's time to read/write to your sockets. The Perl Cookbook has a good example of this in section 17.13 (Non-Forking Servers).

    Hope you find the above useful. Let me know if it doesn't solve your problem.

    Cheers,
    Paul

      Hello Paul, Thank you for the reply . I did some more reading about syswrite in perldoc but there's nothing about returning errors except the undef value (EAGAIN??). I don't want to use "IO::Whatever" , I want to do this using only low level functions.

      My goal is a low level server, non-blocking, non-forking ,multiple connections ... its working , but i have this problem with the detection of disconnected sockets.

      can you please give me a short example of using getpeername for detection ?

      thanks,
      Shlomi

        Ah, EAGAIN and related issues will make more sense if you understand the underlying system calls, in this case write(2). There are a bunch of reasons a write can fail, and the EAGAIN error status indicates that the other end of the connection was not ready to receive input, which is almost always caused by a big queue of data which the receiving process simply hasn't looked at yet.

        If syswrite returns undef, it will place the reason it returned undef into $!, which if evaluated numerically will yield the current value of the C "errno" variable. You can test for particulr errors explicitly like this:

        use POSIX qw/EAGAIN EFBIG ENOSPC/; # stuff unless (defined(syswrite($socket,$buffer))) { # Oops, didn't write. How come? if ($! == EAGAIN) { # Nonblocking and socket not yet ready... } elsif ($! == EFBIG) { # Writing to a file that is too big for our filesystem. } elsif ($! == ENOSPC) { # Ooops, writing to a file and the disk is full. } else { # One of the other dozen or so reasons a write can fail. } }
        Now, in practice, you rarely need to worry about testing for errors like this. Blocking connections either work or fail permanently(Footnote 1). With non-blocking connections, if you make good use of the select(2) system call, your process will be told when sockets are ready to be read/written to. IO::Select is a wrapper to the select(2) system call which makes it a little more managable.

        An excellent example of the skeleton needed for a non-blocking, non-forking server can be found in The Perl Cookbook, Section 17.13.

        As to your original question of an example of using getpeername for detection, here's a short example:

        unless (defined(syswrite($socket,$buffer))) { # Oh dear, couldn't write. Could it be that I'm # no longer connected? if (defined(getpeername($socket))) { # Yup, they're still there. Must be a different error. } else { # Oops, the other side went away. } }
        I would strongly suggest using IO::Socket rather than using getpeername, simply because if($socket->connected) is much more understandable than the code above.

        Hope that all this helps. I haven't had my morning coffee yet, so some bits might be a little unclear. Feel free to quiz me more if you like.

        Cheers,
        Paul

        (Footnote 1) Not entirely true. Blocked reads and writes can be interrupted by signals, and I can't remember off the top of my head if perl automatically restarts the system call once you've dealt with the signal.

Re: How do i detect that the client has disconnected ? (i'm using sysread/write)
by entropy (Sexton) on Oct 05, 2001 at 02:53 UTC
    The select() function will tell you when there is data waiting to be read on a socket. If the connection is lost, select() will lie and say there is something to be read. When you try to read the line, sysread will return undef.
    my $bit_in = ''; my $r_bit; vec($bit_in, fileno($f), 1) = 1; while(1) { select($r_bit = $bit_in, undef, undef, tick_len); # if select said there was data... if(vec($r_bit,fileno($f),1)) { my $in; # connection lost if sysread returns undef return unless $f->sysread($in, 1); # otherwise, it's good data $str .= $in; last if $in eq "\n"; } }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-03-19 10:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found