Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #38967 > unrolled thread
| Started by | Andreas Leitgeb <avl@logic.at> |
|---|---|
| First post | 2019-05-29 11:03 +0000 |
| Last post | 2019-06-01 16:08 +0200 |
| Articles | 10 — 7 participants |
Back to article view | Back to comp.lang.java.programmer
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
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2019-05-29 11:03 +0000 |
| Subject | server-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]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2019-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]
| From | Joerg Meier <joergmmeier@arcor.de> |
|---|---|
| Date | 2019-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]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2019-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]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2019-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]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2020-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]
| From | Martin Gregorie <martin@mydomain.invalid> |
|---|---|
| Date | 2019-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]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2019-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]
| From | trisha guillot <guillottrisha347@gmail.com> |
|---|---|
| Date | 2019-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]
| From | Marcel Mueller <news.5.maazl@spamgourmet.org> |
|---|---|
| Date | 2019-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