Fenrir
Fenrir

Reputation: 41

(Java, Socket) BufferedReader blocks thread, unable to .close()

So I wrote a Client-Server-application for my raspberry pis - to handle multiple clients on the server I always open a new "ClientMessageListener"-thread for every client-socket.

I tried to create a destroy-chain which is called when I want the ServerSocket to shutdown. It iterates through every thread and calls the destroy-method of the ClientMessageListener which should close the connection-resources and then the socket itself.

My client-handlers look like this:

package com.imnos.piserver.server.serversocket.client;

import com.imnos.piserver.server.serversocket.ServerRequestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
* @author simon
*/
public class ClientMessageListener implements Runnable {

    private static final ServerRequestController SRC
            = ServerRequestController.getInstance();

    private Socket clientSocket = null;

    private PrintWriter out = null;
    private InputStreamReader inputStream = null;
    private BufferedReader in = null;

    ClientMessageListener(final Socket clientSocket) {
        this.clientSocket = clientSocket;
        this.initDataStream();
    }

    /**
     * @return
     */
    synchronized boolean destroyClientMessageListener() {

        if (this.clientSocket == null) {
            return false;
        }

        if (this.in != null) {

            try {

                this.in.close(); // Method stucks here

            } catch (IOException ignore) {
                ignore.printStackTrace();
            } finally {
                this.in = null;
            }

        }

        if (this.inputStream != null) {

            try {

                this.inputStream.close();

            } catch (IOException ignore) {
                ignore.printStackTrace();
            } finally {
                this.inputStream = null;
            }

        }

        if (this.out != null) {

            this.out.close();
            this.out = null;

        }

        return true;
    }

    /**
     * @return
     */
    private synchronized boolean initDataStream() {

        if (this.clientSocket == null) {
            return false;
        }

        if (this.clientSocket.isClosed()) {
            return false;
        }

        try {

            this.out = new PrintWriter(
                    this.clientSocket.getOutputStream(), true);

            this.inputStream = new InputStreamReader(
                    this.clientSocket.getInputStream());

            this.in = new BufferedReader(this.inputStream);

            return true;

        } catch (IOException ex) {

            this.destroyClientMessageListener();
            ex.printStackTrace();

        }

        return false;
    }

    /**
     *
     */
    @Override
    public void run() {

        if (in != null) {

            String strInput;

            try {

                while ((strInput = this.in.readLine()) != null) {

                    final boolean success
                        = SRC.handleIncoming(
                            this.clientSocket, strInput);

                }

            } catch (IOException ignore) {
                ignore.printStackTrace();
            }

        }

    }

}

Everything works fine and I expected the this.in.readLine()-call to throw an IOException when I close the resource in the destroy()-method so the thread just ends. But instead the destroy-method blocks when calling this.in.close() and absolutely no Exception is thrown.

Even Thread.getCurrentThread.interrupt() does not work and I have no idea why. Is there a clean solution to close the resources and end the run()-method?

Upvotes: 1

Views: 640

Answers (1)

user207421
user207421

Reputation: 310911

Shutdown the socket for input. That will cause readLine() to return null, which will cause the thread that is reading the socket to close it and exit.

Upvotes: 1

Related Questions