The client for some time working with the server on the sockets. The client decides to shut down (for example, crashing a hung application).

How to find out from the server that the socket is no longer valid and can be discarded? socket.isClosed() side socket.isClosed() always returns false , even if the client has already called socket.close() ?

    3 answers 3

    The isConnected method will help solve the problem. Returns TRUE if the client has closed the connection.

     public class MyServer { public static final int PORT = 12345; public static void main(String[] args) throws IOException, InterruptedException { ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(PORT); Socket s = ss.accept(); Thread.sleep(5000); ss.close(); s.close(); } } public class MyClient { public static void main(String[] args) throws IOException, InterruptedException { Socket s = SocketFactory.getDefault().createSocket("localhost", MyServer.PORT); System.out.println(" connected: " + s.isConnected()); Thread.sleep(10000); int read = s.getInputStream().read(); if(read == -1) System.out.println("Socket disconnected"); else System.out.println(read); } } 

    ps. if I'm not mistaken, if the client has disconnected, then Input/OutputStream will return IOException

    UPD

    • isConnected() true if the socket was successfully connected to the server. Closing a socket does not clear the connection state, which means this method returns true for a closed socket (see IsClosed ()) if it was successfully connected before it was closed.

    • isClosed() Returns the closed state of the socket. those. tells you whether you closed this socket. As long as you have it, it returns false.

    • isConnected() - if the connection is closed, then

    • read() returns -1 if there is no data from the stream, for example, is not available or has reached the end of the stream. This method blocks the stream until the entire stream is read, either the end of the stream is reached, or an exception is thrown.
      Note from @Regent: If you do not specify a timeout, then everything will hang for an unknown time.

    • readLine() returns null

    then you need to check the status of the trace in the following way:

     int read = s.getInputStream().read(); if(read == -1) System.out.println("disconnected"); else System.out.println(read); 

    pps isConnected() will not tell if the client has fallen off.

    • @Regent you correctly pointed out the error. corrected. thank! - Senior Pomidor
    • On health. We need to “figure it out” with the first paragraph: "The isConnected method will help solve the problem. Returns TRUE if the client has closed the connection." Also, I think it is worth noting that the read() method not only blocks the stream, but will also return -1 only if the second socket has been closed correctly. Otherwise, the code on read() hang for an unknown time how long (unless the timeout is set before this, then how much). - Regent

    There is only one reliable method to determine whether a client is connected or not - this is something to send and receive an answer to. If no one writes to the connection, then it may hang for a long time. Yes, TCP has KeepAlive, which does just that, but it is configured for very long intervals (from a few hours).

    Therefore, if you need to determine with guarantee that the user has already fallen off, enter the so-called "pings". They can be both server and client (that is, who is the initiator). One side ensures that once a minute (hour / second) a ping request is sent. The second should respond to it as quickly as possible with a pong (these are conditional names. At the protocol level, this could be FF and FE bytes for example). If by the time of sending the next ping did not come pong - then the second side either came down, or maybe working, but does not have time (yes, if you send a ping once a second, and the server and client are at different points of the globe, it all works through 56k modem, then this is a bad decision :) Choose the frequency reasonably. I think there will usually be plenty of minutes).

    After you implement all this, even isConnected in the example from @Senior Automator will work as it should.

    But, after testing the @Senior Automator solution, you can say that it works the same way. And yes, it will most likely work for you - since you will most likely be testing on localhost. Even in a regular LAN, it will usually work fine. But it is enough to go beyond the limits of the usual lokalki - everything ... A drunk tractor driver will move the cable, it is soldered back and if at this moment your client server did not send anything - they may not even know and continue to work :)

    • No, it does not work "and so", even on localhost. Just because the socket's isConnected() call determines whether connect was successful. The client’s close() call does not affect the status returned by isConnected() on the socket (both server and client). - Regent
    • Yes, apparently I need to tighten the basic knowledge of Java. Although .. - KoVadim
    • Speech about the last two paragraphs regarding the Senior Automator solution, with which I strongly disagree. When writing a comment, I used the following things: 1. The personal test isConnected . 2. Documentation on this method. 3. The source code of the class Socket . 4. this and these responses to enSO. - Regent
    • With the creation of ping-a (keepalive) in the application, I fully agree and that is what I use. Keepalive in TCP itself is optional and disabled by default. You can enable it using the setKeepAlive(boolean) method, but I don’t know if this is better than the implementation of my keepalive. For example, I do not know how to set the periodicity of sending keepalive to TCP, and whether it can be done at all in Java. - Regent
    • you can ask. At least by means of OS. But this keepAlive test that the channel is working, not the services at its ends. Yes, when the services are closed, the channel too, but ... There is one more space - by default there are very long timeouts. - KoVadim

    A simple check of the properties of this problem is not solved. The fact is that in the passive state, the TCP protocol does not transmit anything - and therefore there is no way to know in a reasonable time whether the client is still connected or something happened to it.

    Only the active connection can determine the client's state - and there are two approaches here.

    Approach the first - a ping.

    The meaning of this approach is to allow the TCP driver to diagnose a disconnection. The TCP driver, in turn, can do this if one of three conditions is met:

    1. RST package arrived
    2. The ICMP packet came with an error message (I personally don’t know if these packets are used by common TCP drivers, just for completeness)
    3. The limit of attempts to send data has been exceeded.

    The first two methods of detecting a disconnection are unreliable, so it remains to think about the third. In order to exceed the limit of attempts to send data, TCP must transmit this same data. So, you need to periodically write something to the socket. As long as data is written to the socket, a disconnection will be detected. But if the connection is idle, it makes sense to start periodically recording messages there that will be ignored by the other party. This is called, conditionally, a PING message.

    This method is the easiest - just periodically write the timer to the socket, then everything will happen by itself.

    Second approach - keepalive messages

    The point of this approach is to determine the disconnection before the TCP driver can. For this purpose, a timer is introduced that counts the time from receiving the last byte through a socket. After each read from the socket, the timer starts counting again.

    In this scheme, the client will be disconnected after a certain time after it is "silent". If this is undesirable for the client, it should periodically send "empty" messages that will be ignored by the server, but reset the disconnect timer. Such messages are called keepalive messages.

    This method is more complicated than the past, because it requires timers on both sides of the connection.


    About the combination of approaches. If it is necessary to check the status of the connection from both sides, then the option is possible when the server sends empty messages - and the client only accepts them. In this case, on the server it is enough to periodically write to the socket - and on the client you will need to do a break connection timer. Or vice versa. In this case, the same message will behave both as a ping message and as a keepalive message.

    When using the same approach, empty packages will inevitably walk in both directions.


    About the answers to the "ping" ("pongs"). On their own, “pongs” are not needed to test for disconnection - and without them, disconnection is perfectly detected. But pongs protect against another problem — some clients may (as a result of an error) put the connection to a half-open state when they can only read — but no longer send packets. If the server is not properly implemented, the connection may be permanently stuck in this state.

    About replies to keepalive messages. By themselves, keepalive messages, if used in both directions, perfectly determine both the disconnection of the connection and its getting stuck in the "half-open" state. But the introduction of mandatory responses to keepalive messages allows the client and server to have different timer interval settings.