Socket closed before able to read from ObjectInputStream(BufferedInputStream(Socket.getInputStream))

StackOverflow https://stackoverflow.com/questions/18510723

  •  26-06-2022
  •  | 
  •  

Question

I have written a small Client/Server Program which already worked once but after adding Threads and some real input Data to it, i always get a closed Socket before being able to read the Object (the String). The Program always Prints "Client has already closed Connection!" from Function handleConnection in the ProcessDataThread.

ClientCode:

synchronized private static void sendToServer(){
        Socket clientSocket = null;
    BufferedOutputStream socketOut = null;
        ObjectOutputStream out = null;
    try{ 

        String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";

        Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);

        //TODO load these from file
        clientSocket = new Socket( "10.0.2.2", 7777);
        socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
        out = new ObjectOutputStream(socketOut);
        out.writeObject(xmlToSend);
        out.flush();

    }catch(Exception ex){
        Log.e(TAG, "Could not write File to Server.", ex);
    }
    finally{
        try{
            if(clientSocket != null){
                clientSocket.close();
            }
            if(out != null){
                out.close();
            }
        }catch(IOException ex){
            Log.e(TAG, "Could not close Socket.");
        }
    }
}

ServerCode:

ReceiverThread:

public void run()
{
    try {
        ServerSocket server = new ServerSocket(port);
        //Only block for 10 Seconds and try again
        server.setSoTimeout(10000);
        while(!server.isClosed() && !stopped){
            //Run
             Socket client = null;
              try
              {
                client = server.accept();
                System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
                new ProcessDataThread(client).start();
              }
              catch( SocketTimeoutException tx){
                  //nothing
              }
              catch ( IOException e ) {
                e.printStackTrace();
              }
              finally {
                if ( client != null )
                  try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
              }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

}

ProcessDataThread:

public class ProcessDataThread extends Thread {

Socket client;

public ProcessDataThread(Socket sock) {
    // xmlToProcess = xmlString;
    this.client = sock;
}

private String handleConnection() {

    BufferedInputStream socketIn = null;
    ObjectInputStream in = null;
    String xmlToProcess = null;
    try {
        if(!client.isClosed()){
            System.out.println("Trying to read from Stream;");
            socketIn = new BufferedInputStream(client.getInputStream());
            in = new ObjectInputStream(socketIn);

            Object xmlString = in.readObject();
            System.out.println("Read some Object from Stream:" + xmlString.toString());
            if (xmlString instanceof String) {
                xmlToProcess = (String) xmlString;
                System.out.println("Received the following XML:\n" + xmlToProcess);
            }
        }else{
            System.out.println("Client has already closed Connection!");
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (EOFException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (socketIn != null) {
                socketIn.close();
            }
            if(client != null){
                client.close();
            }
        } catch (IOException ioex) {
            ioex.printStackTrace();
        }
    }
    return xmlToProcess;
}

@Override
public void run() {

    String xmlToProcess = handleConnection();

    if (xmlToProcess == null || xmlToProcess.isEmpty()) {
        // Es konnte kein String vom Client gelesen werden.
        return;
    }

            System.out.println(xmlToProcess);
 }
}

I made some changes with jboi's Suggestions. This is what i got now. The error stays the same. I don't even get to reading the Stream in the Server because client.getClosed() is always true!

In the Client Code:

clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();

in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
    //Wait for the Server to Close the Connection
}

In the Server Code

socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
    xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}

out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();
Was it helpful?

Solution 2

It is very probable that your client has closed the socket in the finally block before the server was able to read the data.

In your clients finally block you should use socket.shutdownOutput, then read on the client all incoming data till EOF and then close the socket.

On your server you read till EOF and then send an object as kind of acknowledge, e.g. Number of bytes in the message. You also end the send with socket.shutdownOutput() as you've done at the client. This puts again an EOF at the end of the data. This EOF is received by the client and it will finally close the socket.

OTHER TIPS

The issue seems to be the client and server are unable to identify each others state:

  1. Client sending data to server, where server has closed the connection
  2. Server sending/reading data to client , where client has closed the connection

Either are unable to coordinate with each other, solutions could be to establish a proper state machine. Some examples in Google if you search for (client and server state machine) gives mathematically definite state machine examples for your application: hope this comment helps.

Hence it's not useful to look into this problem in solution perspective and probably start using protocols in place like : telnet etc .

Ok now i'm feeling stupid. I closed the Socket inside the Server Code myself. After accepting a connection the following is executed inside the finally Block:

try {
    client.close();
} catch (IOException e) {
    e.printStackTrace();
}

The reason that there is this finally Block was because i didn't use Threads before so the ReceiverThread also did handle the Connection and therefore close the socket after using it. I then moved the code to the new Thread and forgot to remove that finally block!

You can't use a buffered input stream and another kind of stream on the same socket. The buffered stream will steal data from the other one. Make up your mind. The ObjectInputStream will do everything you need. Just use that.

EDIT Re your edit, 'socket closed' means that you closed your socket and then continued to use it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top