David Kramer
David Kramer

Reputation: 11

Java TCP Client Unresponsive when working outside eclipse

I'm having trouble getting my client Java application to be responsive, when connecting to a local TCP server. The server shows the client has connected, but the client receives no updates from server and remains static. However, it works just fine when I run both inside of Eclipse. But after exporting each to executable jar files, I have no luck. I have looked around and thought it might be my windows firewall, which I have disabled, but it still doesn't work.

The TCP server is running locally and clients are just connecting by whatever local IP address the server machine has. Even testing both client and server on the same machine (but outside of Eclipse), the client still remains unresponsive, yet the server shows it has connected a client. I just don't know what eclipse is doing to make the app run different to work, than outside it. Any suggestions are much appreciated! Thank you.

The way the communication is setup is we have a main JSON object that contains a command, that the client receives. Based on the command, the client reacts somehow. On server, each client is an independent thread. When the client first connects, the server adds them and creates a new ServerClient which links the communication back and forth. Upon joining, the server should echo all connected clients to whoever joined, and it will display in the client GUI. There's much more involved, but this is the basic client-server communication link.

Server:

/**
 * Constructs a new Server with a link to the ServerApp.
 * @param app - Target ServerApp
 */
public Server(ServerApp app) {
    this.app = app;
    clients = new HashMap<>();
    serverDir = new ServerDirector(this);
}

/**
 * Main server loop. Waits and listens for new clients.
 */
public void run() {
    while (running) {
        try {
            // wait and accept new clients
            app.log("Waiting for client...");
            addClient(serverSocket.accept());
        } catch (SocketException e) {   // terminate if socket is closed!
            running = false;
        } catch (EOFException e) {
            running = false;
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * Opens server socket on defined PORT.
 * @throws IOException
 */
public void open() throws IOException {
    serverSocket = new ServerSocket(portNo);
}

/**
 * Adds a client to the clients map.
 * @param socket - Socket to allow server client to connect
 * @throws IOException
 */
public void addClient(Socket socket) throws IOException {
    if (clients.size() < MAX_CLIENTS) {
        int ID = serverDir.getPlayers().size();
        System.out.println("Socket: " + socket);
        ServerClient sc = new ServerClient(ID, socket, this);
        sc.open();
        sc.start();
        sc.echoID(); // echo ID to main client thread
        NewJSONObject k = new NewJSONObject(ID, Keys.Commands.CONNECT); // send connection status!
        k.put(Keys.CONNECT_STATUS, 1);  // connection is good!
        sc.getIOHandler().send(k);
        clients.put(ID, sc);
    } else {
        System.out.println("Client limit reached. Client connection refused!");
    }
}

Client:

    /**
 * Constructs a client with link to main app, and specified ID and socket.
 * @param app - ClientApp
 * @param ID - ID to assign
 * @param socket - Socket to connect to
 */
public Client(ClientApp app, int ID, Socket socket) {
    this.app = app;
    this.ID = ID;
    this.socket = socket;
}

/**
 * Starts this thread.
 */
public void start() {
    running = true;
    super.start();
}

/**
 * Main thread loop. Listens to input received on InputStream.
 */
public void run() {
    while (running) {
        try {
            ioHandler.receive((JSONObject)streamIn.readObject());
        } catch (EOFException | SocketException e) {
            running = false;
            try {
                terminate();
            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

/**
 * Attempts to connect to the specified socket.
 * @param socket - Socket to connect to.
 * @throws IOException
 */
public void connect(Socket socket) throws IOException {
    this.socket = socket;
    open();
    connected = true;
}

/**
 * Opens I/O streams.
 * @throws IOException
 */
public void open() throws IOException {
    streamOut = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
    streamOut.flush();
    streamIn = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
}

So once the client connects, I have a Server GUI which has a list of all clients connected. Then the ServerDirector (which handles packets) sends "addPlayer" command, which client interprets and adds the specified name in the JSON packet to the GUI. The name appears on client, and then once 2+ players join, further commands are sent to transition between various states. All works fine inside Eclipse, but once apps are external jars, the client remains static, even though the server shows the client is indeed connected. The client just doesn't receive any packet updates, when running outside Eclipse.

Upvotes: 0

Views: 200

Answers (1)

David Kramer
David Kramer

Reputation: 11

I figured out the issue. All of the resource files that the application uses such as player sprites, weren't in the correct directory when exporting from eclipse, which lead to multiple FileNotFoundExceptions and NullPointerExceptions and caused the client not to run as other components were dependent on the res files. Simply adding the res folder to the jar solved the problem!

Upvotes: 1

Related Questions