Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #38967 > unrolled thread

server-side Socket does not recognize broken connection.

Started byAndreas Leitgeb <avl@logic.at>
First post2019-05-29 11:03 +0000
Last post2019-06-01 16:08 +0200
Articles 10 — 7 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  server-side Socket does not recognize broken connection. Andreas Leitgeb <avl@logic.at> - 2019-05-29 11:03 +0000
    Re: server-side Socket does not recognize broken connection. Eric Sosman <esosman@comcast-dot-net.invalid> - 2019-05-29 08:30 -0400
    Re: server-side Socket does not recognize broken connection. Joerg Meier <joergmmeier@arcor.de> - 2019-05-29 14:58 +0200
      Re: server-side Socket does not recognize broken connection. Andreas Leitgeb <avl@logic.at> - 2019-05-29 14:50 +0000
        Re: server-side Socket does not recognize broken connection. Eric Douglas <e.d.programmer@gmail.com> - 2019-05-29 08:22 -0700
          Re: server-side Socket does not recognize broken connection. Andreas Leitgeb <avl@logic.at> - 2020-01-30 15:22 +0000
        Re: server-side Socket does not recognize broken connection. Martin Gregorie <martin@mydomain.invalid> - 2019-05-29 16:06 +0000
    Re: server-side Socket does not recognize broken connection. Eric Douglas <e.d.programmer@gmail.com> - 2019-05-29 07:14 -0700
    Re: server-side Socket does not recognize broken connection. trisha guillot <guillottrisha347@gmail.com> - 2019-05-31 20:13 -0700
    Re: server-side Socket does not recognize broken connection. Marcel Mueller <news.5.maazl@spamgourmet.org> - 2019-06-01 16:08 +0200

#38967 — server-side Socket does not recognize broken connection.

FromAndreas Leitgeb <avl@logic.at>
Date2019-05-29 11:03 +0000
Subjectserver-side Socket does not recognize broken connection.
Message-ID<slrnqespnm.cfl.avl@logic.at>
I have a ServerSocket on some port. whenever ".accept()" returns a
connection, it goes to a loop that (among doing other stuff) polls
the socket's input stream's ".available()" and if it returns > 0
it reads and processes that data.  (SSCCE at end of post)

A client (e.g. using plain old "telnet" on unix) connects, types a
bit, then breaks the connection using Ctrl-] and "close", and is back
on the shell. (closing the terminal window that's running telnet
has same effect, ditto killing the telnet process - apparently
whatever breaks, or even properly shuts down the connection from
client side.)

The Socket on server side, however keeps reporting 0 on .available(),
rather than throwing some exception for the broken socket.

Single stepping the .available() method (class AbstractPlainSocketImpl)
shows that it just never receives the ConnectionResetException, and thus
won't ever get to throw new IOException("Stream closed.") itself.
Field resetState never changes away from CONNECTION_NOT_RESET.

What am I doing wrong wrt. EOF-detection in ".available()" ?

PS: The real code does more interesting stuff while no input is available,
so it cannot wait blockingly.  The real code also has other exits from the
loop (based on input received), but that's not relevant for this SSCCE.

PS: unlike most of my recent posts, this one is *not* Java11-related.


SSCCE:  ServerTest.java

import javax.net.ServerSocketFactory;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.InputStream;
import java.io.IOException;

public class ServerTest {
   public static void main(String[] args) throws IOException,InterruptedException {

      ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(65432);
      Socket clientSocket = serverSocket.accept();
      InputStream is = clientSocket.getInputStream();

      while (true) {
         if (is.available() > 0) {
            System.out.println( is.read() );
         }
         Thread.sleep(100);
      }
   }
}

[toc] | [next] | [standalone]


#38969

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2019-05-29 08:30 -0400
Message-ID<qclu0s$gh$1@dont-email.me>
In reply to#38967
On 5/29/2019 7:03 AM, Andreas Leitgeb wrote:
> I have a ServerSocket on some port. whenever ".accept()" returns a
> connection, it goes to a loop that (among doing other stuff) polls
> the socket's input stream's ".available()" and if it returns > 0
> it reads and processes that data.  (SSCCE at end of post)
> 
> A client (e.g. using plain old "telnet" on unix) connects, types a
> bit, then breaks the connection using Ctrl-] and "close", and is back
> on the shell. (closing the terminal window that's running telnet
> has same effect, ditto killing the telnet process - apparently
> whatever breaks, or even properly shuts down the connection from
> client side.)
> 
> The Socket on server side, however keeps reporting 0 on .available(),
> rather than throwing some exception for the broken socket.
> 
> Single stepping the .available() method (class AbstractPlainSocketImpl)
> shows that it just never receives the ConnectionResetException, and thus
> won't ever get to throw new IOException("Stream closed.") itself.
> Field resetState never changes away from CONNECTION_NOT_RESET.
> 
> What am I doing wrong wrt. EOF-detection in ".available()" ?

     Using available(), I think.  :)

     available() reports (or estimates) the number of bytes that can be
read without blocking, that is, the number of bytes already received
and buffered.  "My buffer is empty right now" is not the same thing as
"There will never be any more input," so available()==0 is not a test
for EOF.  It is true that once you've read all the bytes that will
ever appear you will find available()==0, but the implication is
one-directional.

     To discover that the socket has been closed, I think you must
actually attempt to read something.  The documentation for available()
doesn't say so explicitly -- but then, there are so many different
implementations of InputStream that documenting the exact behavior
of all of them would be daunting or perhaps even impossible.

> PS: The real code does more interesting stuff while no input is available,
> so it cannot wait blockingly.  The real code also has other exits from the
> loop (based on input received), but that's not relevant for this SSCCE.

     One approach (there might be others) would be to create a thread
that just calls read() until it gets an exception, depositing the input
in a Queue (or similar) that the main line can poll() without blocking.
At EOF or other exception, the reading thread would enqueue a "poison
pill" to alert the main line that something's amiss.

-- 
esosman@comcast-dot-net.invalid
Six hundred two days to go.

[toc] | [prev] | [next] | [standalone]


#38970

FromJoerg Meier <joergmmeier@arcor.de>
Date2019-05-29 14:58 +0200
Message-ID<1v9ncmqz4ep4j$.1mdftm8twalol$.dlg@40tude.net>
In reply to#38967
On Wed, 29 May 2019 11:03:18 -0000 (UTC), Andreas Leitgeb wrote:

> PS: The real code does more interesting stuff while no input is available,
> so it cannot wait blockingly.  The real code also has other exits from the
> loop (based on input received), but that's not relevant for this SSCCE.

In addition to Erics excellent answer, I would like to add that I'm pretty
certain that you can not write code like that without resorting to
blocking. You may want to look at NIO or higher level frameworks if you can
not astract the blocking aspect away on your own for some reason.

Liebe Gruesse,
		Joerg

-- 
Ich lese meine Emails nicht, replies to Email bleiben also leider
ungelesen.

[toc] | [prev] | [next] | [standalone]


#38972

FromAndreas Leitgeb <avl@logic.at>
Date2019-05-29 14:50 +0000
Message-ID<slrnqet716.cfl.avl@logic.at>
In reply to#38970
Joerg Meier <joergmmeier@arcor.de> wrote:
> On Wed, 29 May 2019 11:03:18 -0000 (UTC), Andreas Leitgeb wrote:
>> PS: The real code does more interesting stuff while no input is available,
>> so it cannot wait blockingly.  The real code also has other exits from the
>> loop (based on input received), but that's not relevant for this SSCCE.
> In addition to Erics excellent answer,

Thanks also to Eric!

> I would like to add that I'm pretty
> certain that you can not write code like that without resorting to
> blocking.

Watching the Java server with strace (on linux), I see that Java calls
the system:
  ioctl(6, FIONREAD, [0])     = 0

Now I'm going to read up on why this syscall wouldn't report a broken socket,
and what other syscall (short of actually reading and risking to block)
would allow me to tell idle from broken.

Calling "lsof" on the Java process' pid shows that the OS does know the
socket is broken:
java    29340  avl    6u  IPv6          113368285       0t0       TCP
   localhost:65432->localhost:58500 (CLOSE_WAIT)

> You may want to look at NIO or higher level frameworks if you can
> not astract the blocking aspect away on your own for some reason.

A separate thread to read blockingly and shovel the results into a 
Queue (as Eric suggested) is plausible, assuming that it works. 
Trying to replace inputStreams by nio is also on my "TO CHECK" list.

Thanks anyway for pointing me in the direction that available() alone
just isn't designed to recognize broken sockets.

I consider my question answered. Thanks!

[toc] | [prev] | [next] | [standalone]


#38973

FromEric Douglas <e.d.programmer@gmail.com>
Date2019-05-29 08:22 -0700
Message-ID<afae8c57-f998-433a-84fa-16b64b400185@googlegroups.com>
In reply to#38972
On Wednesday, May 29, 2019 at 10:50:25 AM UTC-4, Andreas Leitgeb wrote:
> A separate thread to read blockingly and shovel the results into a 
> Queue (as Eric suggested) is plausible, assuming that it works. 


The SocketServer has the setSoTimeout() method to tell it how long to listen for the client connection on the accept() method.  This method returns an instance of Socket which is connected to a client instance of Socket.
The Socket class also has setSoTimeout, so this can be called from client and/or server.

"Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout."

So it seems zero is the default timeout, which should throw a timeout exception based on when the OS says a socket is timed out, checking available will tell you if there's any data to be read on the socket but won't tell you if the other end is still connected, attempting to read the socket will grab any data and throw an exception if the other side is disconnected, the read attempt will wait and block for the length of time set by the timeout method, and if you have reason to not block the socket you'll need a secondary method to determine if the other side is still active.

[toc] | [prev] | [next] | [standalone]


#39283

FromAndreas Leitgeb <avl@logic.at>
Date2020-01-30 15:22 +0000
Message-ID<slrnr35t4r.hr6.avl@logic.at>
In reply to#38973
Eric Douglas <e.d.programmer@gmail.com> wrote:
> The Socket class also has setSoTimeout, so this can be called from client and/or server.

Yes, thanks.  The solution I ended up with uses exactly that.

If really curious, look at https://github.com/mabe02/lanterna/pull/435
(the PR is merged and working fine)

[toc] | [prev] | [next] | [standalone]


#38974

FromMartin Gregorie <martin@mydomain.invalid>
Date2019-05-29 16:06 +0000
Message-ID<qcmall$msh$1@news.albasani.net>
In reply to#38972
On Wed, 29 May 2019 14:50:14 +0000, Andreas Leitgeb wrote:

> Watching the Java server with strace (on linux), I see that Java calls
> the system:
>   ioctl(6, FIONREAD, [0])     = 0
> 
> Now I'm going to read up on why this syscall wouldn't report a broken
> socket, and what other syscall (short of actually reading and risking
> to block) would allow me to tell idle from broken.
> 
A quick look at the man pages for ioctl(2) and ioctl_list(2) didn't tell 
me a lot.

It seems to me that Eric's suggestion of using a blocking read to fill a 
queue and driving your mail processing loop off that is most likely the 
way to go.


-- 
Martin    | martin at
Gregorie  | gregorie dot org

[toc] | [prev] | [next] | [standalone]


#38971

FromEric Douglas <e.d.programmer@gmail.com>
Date2019-05-29 07:14 -0700
Message-ID<9b92a0e6-3558-4dda-9677-98ad8925e63c@googlegroups.com>
In reply to#38967
On Wednesday, May 29, 2019 at 7:03:29 AM UTC-4, Andreas Leitgeb wrote:
> I have a ServerSocket on some port. whenever ".accept()" returns a
> connection, it goes to a loop that (among doing other stuff) polls
> the socket's input stream's ".available()" and if it returns > 0
> it reads and processes that data.  (SSCCE at end of post)
> 
> A client (e.g. using plain old "telnet" on unix) connects, types a
> bit, then breaks the connection using Ctrl-] and "close", and is back
> on the shell. (closing the terminal window that's running telnet
> has same effect, ditto killing the telnet process - apparently
> whatever breaks, or even properly shuts down the connection from
> client side.)
> 
> The Socket on server side, however keeps reporting 0 on .available(),
> rather than throwing some exception for the broken socket.
> 
> Single stepping the .available() method (class AbstractPlainSocketImpl)
> shows that it just never receives the ConnectionResetException, and thus
> won't ever get to throw new IOException("Stream closed.") itself.
> Field resetState never changes away from CONNECTION_NOT_RESET.
> 
> What am I doing wrong wrt. EOF-detection in ".available()" ?
> 
> PS: The real code does more interesting stuff while no input is available,
> so it cannot wait blockingly.  The real code also has other exits from the
> loop (based on input received), but that's not relevant for this SSCCE.
> 
> PS: unlike most of my recent posts, this one is *not* Java11-related.
> 
> 
> SSCCE:  ServerTest.java
> 
> import javax.net.ServerSocketFactory;
> import java.net.ServerSocket;
> import java.net.Socket;
> import java.io.InputStream;
> import java.io.IOException;
> 
> public class ServerTest {
>    public static void main(String[] args) throws IOException,InterruptedException {
> 
>       ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(65432);
>       Socket clientSocket = serverSocket.accept();
>       InputStream is = clientSocket.getInputStream();
> 
>       while (true) {
>          if (is.available() > 0) {
>             System.out.println( is.read() );
>          }
>          Thread.sleep(100);
>       }
>    }
> }

I haven't stress tested mine, but it seems to work.  I just set up a socket connection for one machine to send text to one or two other machines.
First I create one listener as an instance of java.net.ServerSocket with a specific port, and assign setSoTimeout().  Then I run this try block.
try {
     while (keepServerAlive) {
          try {
               new SocketServer(listener.accept(), clientNumber++).start();
          } catch (final SocketTimeoutException e) {
               // end extra thread - there's always one idle thread waiting for new connections
          }
     }
} finally {
     listener.close();
}
keepServerAlive is a boolean variable I can set elsewhere to shut down the server side.  clientNumber is a simple int for tracking the number of clients connected since the server was started.  This loop should create a new SocketServer whenever accept() succeeds, failure should hit the timeout.

SocketServer is a subclass set up like this.
private static class SocketServer extends Thread {
     private final Socket socket;
     private final int clientNumber;

     public SocketServer(final Socket socket, final int clientNumber) {
          this.socket = socket;
          this.clientNumber = clientNumber;
     }
     @Override
     public void run() {
          PrintWriter out = null;
          try {
               final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
               out = new PrintWriter(socket.getOutputStream(), true);
// out variable can be referenced elsewhere to send messages to this client
// this thread will also die when flag is set to shut down server
               while (keepServerAlive) {
                    final String input = in.readLine();
// check if client not responding, other value to end session may be sent into this condition
                    if (input == null) {
                         break;
                    }
               }
          } catch (final IOException e) {
// I crash here if client socket terminates
// finally, run cleanup to close the PrintWriter if not null and close the socket

The rest of that class just involves the logic to direct the output of a Blender log.  The client side is a separate class with the mirror logic, creating an instance of Socket with the server name and port, opening it's own InputStreamReader and PrintWriter for 2-way communication, with a background thread running an infinite readLine on the input, checking for null or IOException.  In my case I made a JFrame on the client with a windowClosing listener set to interrupt that background thread, and a JTextArea to display the server messages.

[toc] | [prev] | [next] | [standalone]


#38975

Fromtrisha guillot <guillottrisha347@gmail.com>
Date2019-05-31 20:13 -0700
Message-ID<92ecf367-9f62-4d72-84cf-c9308005ff3c@googlegroups.com>
In reply to#38967
On Wednesday, May 29, 2019 at 4:03:29 AM UTC-7, Andreas Leitgeb wrote:
> I have a ServerSocket on some port. whenever ".accept()" returns a
> connection, it goes to a loop that (among doing other stuff) polls
> the socket's input stream's ".available()" and if it returns > 0
> it reads and processes that data.  (SSCCE at end of post)
> 
> A client (e.g. using plain old "telnet" on unix) connects, types a
> bit, then breaks the connection using Ctrl-] and "close", and is back
> on the shell. (closing the terminal window that's running telnet
> has same effect, ditto killing the telnet process - apparently
> whatever breaks, or even properly shuts down the connection from
> client side.)
> 
> The Socket on server side, however keeps reporting 0 on .available(),
> rather than throwing some exception for the broken socket.
> 
> Single stepping the .available() method (class AbstractPlainSocketImpl)
> shows that it just never receives the ConnectionResetException, and thus
> won't ever get to throw new IOException("Stream closed.") itself.
> Field resetState never changes away from CONNECTION_NOT_RESET.
> 
> What am I doing wrong wrt. EOF-detection in ".available()" ?
> 
> PS: The real code does more interesting stuff while no input is available,
> so it cannot wait blockingly.  The real code also has other exits from the
> loop (based on input received), but that's not relevant for this SSCCE.
> 
> PS: unlike most of my recent posts, this one is *not* Java11-related.
> 
> 
> SSCCE:  ServerTest.java
> 
> import javax.net.ServerSocketFactory;
> import java.net.ServerSocket;
> import java.net.Socket;
> import java.io.InputStream;
> import java.io.IOException;
> 
> public class ServerTest {
>    public static void main(String[] args) throws IOException,InterruptedException {
> 
>       ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(65432);
>       Socket clientSocket = serverSocket.accept();
>       InputStream is = clientSocket.getInputStream();
> 
>       while (true) {
>          if (is.available() > 0) {
>             System.out.println( is.read() );
>          }
>          Thread.sleep(100);
>       }
>    }
> }

[toc] | [prev] | [next] | [standalone]


#38976

FromMarcel Mueller <news.5.maazl@spamgourmet.org>
Date2019-06-01 16:08 +0200
Message-ID<qcu0ti$ogl$1@news4.open-news-network.org>
In reply to#38967
Am 29.05.19 um 13:03 schrieb Andreas Leitgeb:
> A client (e.g. using plain old "telnet" on unix) connects, types a
> bit, then breaks the connection using Ctrl-] and "close", and is back
> on the shell. (closing the terminal window that's running telnet
> has same effect, ditto killing the telnet process - apparently
> whatever breaks, or even properly shuts down the connection from
> client side.)
> 
> The Socket on server side, however keeps reporting 0 on .available(),
> rather than throwing some exception for the broken socket.

Did you enable TCP keepalive? Without this option it may take an 
undefined time until a broken connection is recognized. Simply because 
it is not an error to send no data.

The situation only changes if /you/ send data over the socket. In this 
case the missing TCP ACK will be recognized after some retries.


> Single stepping the .available() method (class AbstractPlainSocketImpl)
> shows that it just never receives the ConnectionResetException, and thus
> won't ever get to throw new IOException("Stream closed.") itself.
> Field resetState never changes away from CONNECTION_NOT_RESET.

This could match with the above case.


> What am I doing wrong wrt. EOF-detection in ".available()" ?

There is no 'EOF condition' when the socket never receive a close from 
the client e.g. because the network connection is interrupted.

If only a process is canceled the operation system should clean up the 
remaining sockets. In this case there should not be a resource leak. (As 
long as the client sockets are not inherited by other still existing 
child processes.)
So you never can rely on that. TCP keepalive is AFAIK the only reliable 
way to identify unexpected client disconnects if you do not send data 
from time to time.


Marcel

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web