6

In my java application, I have a TCP server which sends data generated in my app to all connected clients. For each new socket, I create a new thread. Following is the thread code.

    public void run() {
        try {
            PrintStream printStream = new PrintStream(socket.getOutputStream(), true);
            while (true) {
                if (socket.isClosed()) {
                    break;
                }
                synchronized (DataSource.getInstance()) {
                    printStream.println(DataSource.getInstance().getData());
                    try {
                        DataSource.getInstance().wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Data generating thread writes to DataSoure when new data is available and calls notifyAll() so all threads which handles connected sockets wake up and send available data to clients.

My problem is, even if a client disconnected, socket.isClosed() returns true. So the thread which handles the socket never gets terminated.

Why does this happen? How can I exit the thread when a client gets disconnected?

Lahiru Chandima
  • 22,324
  • 22
  • 103
  • 179

2 Answers2

10

There is no "disconnect" with TCP. A peer can only indicate that it does not want to send anything more (send FIN) but this does not mean that it does not want to receive anything. The other end only realizes that read is unwanted too once it tries it and gets a RST back.

If you take the "don't want to read" as an indicator that the client closed (you might if the application protocol is this way) then you can test if the peer "disconnected" by simply reading from the socket. The system call then returns no error but 0 bytes and this means that there will be no more data from the peer. In Java this case gets translated into an EOFException.

Apart from that a socket does not get closed automatically - only explicitly. isClosed only returns true once the socket is explicitly closed on your local end, not the peer's end. And isConnected will also not tell you if the other end "disconnected", it will only tell you if your end did connect to the peer.

See also Java Socket API: How to tell if a connection has been closed?.

Alex Taylor
  • 8,343
  • 4
  • 25
  • 40
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • I cannot read from the socket because client sends no data. I read the SO answer you pointed and I think I will eventually get an `IOException` when I continuously trying to write to the peer closed socket. Am I correct? – Lahiru Chandima May 31 '15 at 16:15
  • If the clients just sends no data then the connection is still open. The client explicitly indicates that it does not want to send any more data by shutting the connection down on its end. And this information is transferred by using the FIN flag and then read will not block but indicate EOF. No FIN will be send if the OS of the peer crashed or the system got disconnected - in which case the connection is still assumed to be connected. – Steffen Ullrich May 31 '15 at 16:18
  • Actually what I did to break the connection is killing the peer. According to you, the connection will be assumed to be connected. Is there any way I can detect that the client is dead so that I can exit the thread? – Lahiru Chandima May 31 '15 at 16:24
  • If the peer process just gets killed most OS will close the connection, i.e. FIN will be send and EOF will be detected. If you want to detected breakage of connection (cable disconnected etc) you need to use either TCP keep-alive or have your application specific keep alive protocol or just close after some inactivity. – Steffen Ullrich May 31 '15 at 16:27
  • But I cannot read from the socket just to know whether it is connected or not. Since client sends no data, if I try to read while client is alive, it will block. And I will not be able to send the generated data to the client. – Lahiru Chandima May 31 '15 at 16:30
  • You will detect if the client closed also by writing. I really recommend to read the post I've linked to and the discussion on this post. – Steffen Ullrich May 31 '15 at 16:32
-1

You should use isConnected() function instead of isClosed() in order to detect if the remote socket is closed.

Hussein Zawawi
  • 2,907
  • 2
  • 26
  • 44
  • 1
    This won't work. The Java Document for this method has already clarified it: "Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfuly connected prior to being closed." – Jing He Aug 03 '17 at 13:37