Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread hangs when creating ObjectInputStream

Tags:

java

stream

I've got the following code on my server end:

public class ClientThread extends Thread
{
Socket clientSocket;

DataInputStream dis;
ObjectInputStream ois;
DataOutputStream dos;

public ClientThread(Socket acceptedSocket)
{
    clientSocket = acceptedSocket;

    try
    {
        dis = new DataInputStream(clientSocket.getInputStream());
        ois = new ObjectInputStream(clientSocket.getInputStream()); // HANGS HERE
        dos = new DataOutputStream(clientSocket.getOutputStream());
    }
    catch (Exception e)
    {
        System.out.println("ClientThread " + e.getMessage());
    }
}   

Rest of the class omitted

Why does my application freeze when calling the socket inputstream twice, without throwing an exception?

Yes, I could just save the inputstream to an InputStream variable and use that variable to get the desired inputstream type, but I'm curious to why it hangs when being called twice from the socket?

What's the difference? Being called twice doesn't change anything?


EDIT: Even when saving the inputstream to an InputStream variable and using that variable to get the desired inputstream (DataInputStream and ObjectInputStream) it still hangs when called more than once?

Example:

public class ClientThread extends Thread
{
Socket clientSocket;

InputStream is;
DataInputStream dis;
ObjectInputStream ois;
DataOutputStream dos;

public ClientThread(Socket acceptedSocket)
{
    clientSocket = acceptedSocket;

    try
    {
        is = clientSocket.getInputStream();
        dis = new DataInputStream(is);
        ois = new ObjectInputStream(is); // STILL HANGS HERE
        dos = new DataOutputStream(clientSocket.getOutputStream());
    }
    catch (Exception e)
    {
        System.out.println("ClientThread " + e.getMessage());
    }
}   

Rest of the class omitted


Client-side code:

public class LoginLogic_Callable implements Callable<String>
{
Socket socket;
String actionString;
String username;
String password;

public LoginLogic_Callable(Socket sentSocket, String sentUsername, String sentPassword)
{
    socket = sentSocket;
    username = sentUsername;
    password = sentPassword;
}

@Override
public String call() throws Exception 
{
    String userLoginStatus = null;

    try
    {
        DataOutputStream loginUserData = new DataOutputStream(socket.getOutputStream()); 
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        DataInputStream dis = new DataInputStream(socket.getInputStream());

        String[] loginUserInfo = new String[2];

        loginUserInfo[0] = username;
        loginUserInfo[1] = password;

        loginUserData.writeUTF("userlogin");
        oos.writeObject(loginUserInfo);
        loginUserData.flush();
        oos.flush();

        userLoginStatus = dis.readUTF();

        loginUserData.close();
        oos.close();
        dis.close();
    }
    catch (Exception e)
    {
    }   

    return userLoginStatus;
}
}
like image 930
Birdman Avatar asked Feb 18 '14 19:02

Birdman


1 Answers

Just calling getInputStream() isn't 'reading', and it doesn't cause this problem. You can prove that by calling it ten times, or constructing ten DataInputStreams round it. It is the construction of the ObjectInputStream that is causing the problem, and you can prove that by removing the DataInputStream altogether, which you should do anyway: see below.

You're creating an ObjectInputStream. The constructor of ObjectInputStream reads a stream header that is written by the constructor of ObjectOutputStream. As that isn't happening in this code, and presumably not at the peer either, it blocks forever.

For the same reason, you must create the ObjectOutputStream first, before the ObjectInputStream, otherwise again you will have a deadlock.

There seems to be some plan here to use two kinds of stream on the same socket. Don't do that. It won't work, and it isn't necessary, as the object streams have all the same methods as the data streams, in addition to the object reading and writing methods.

EDIT Now that you've posted your client code, what is happening is that the client is deferring creation of the ObjectOutputStream until call() is called. It should be created in the constructor of that class. Otherwise your server side constructor blocks until call() is called at the client. And you still need to get rid of the redundant streams.

like image 76
user207421 Avatar answered Sep 18 '22 16:09

user207421