0

I am wondering why it gets stuck on the following line, but it didn't used to get stuck when I was using a BufferedReader with an InputStreamReader:

input = new ObjectInputStream(socket.getInputStream());

Here is my client code:

import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class MtgTestRunsClient {

    private JFrame frame = new JFrame("MTG Test Runs");

    private static int PORT = 8901;
    private Socket socket;
    //private BufferedReader inFromServer;
    //private PrintWriter outToServer;
    private ObjectInputStream inFromServer;
    private ObjectOutputStream outToServer;
    private Planeswalker planeswalker;

    public MtgTestRunsClient(String serverAddress) throws Exception {

        // Setup networking
        socket = new Socket(serverAddress, PORT);
        //inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //outToServer = new PrintWriter(socket.getOutputStream(), true);
       inFromServer = new ObjectInputStream(socket.getInputStream());
       outToServer = new ObjectOutputStream(socket.getOutputStream());

        planeswalker = new BUGDelverPlaneswalker();
        planeswalker.setOutputToServer(outToServer);

        // Frame content
        JPanel contentPane = new JPanel(new BorderLayout());
        frame.setContentPane(contentPane);
        frame.getContentPane().add(planeswalker.getStatusBar(), BorderLayout.SOUTH);
        frame.getContentPane().add(planeswalker, BorderLayout.CENTER);
    }

    public void play() throws Exception {
        //String response;
        Object response;
        try {
            //response = inFromServer.readLine();
            response = inFromServer.readObject();
            if (response instanceof String ){
                if( ((String)response).startsWith("WELCOME")) {
                    char mark = ((String)response).charAt(8);
                    frame.setTitle("MTG Test Runs - Player " + mark);
                }
            }
            while (true) {
                //response = inFromServer.readLine();
                response = inFromServer.readObject();
                if (response instanceof String ){
                    if (((String)response).startsWith("OPPONENT_MOVED")) {
                        planeswalker.getStatusBar().setStatusString("Opponent "+((String)response).substring(15), false, true);
                    } else if (((String)response).startsWith("GAME_OVER")) {
                        break;
                    } else if (((String)response).startsWith("MESSAGE")) {
                        String messageText = ((String)response).substring(8);
                        planeswalker.getStatusBar().setStatusString(messageText, false, true);
                    }
                }else if(response instanceof Planeswalker){
                    planeswalker.setOpponent((Planeswalker)response);
                }
            }
            outToServer.writeObject("QUIT");
            outToServer.flush();
        }
        finally {
            socket.close();
        }
    }

    private boolean wantsToPlayAgain() {
        int response = JOptionPane.showConfirmDialog(frame,
            "Want to play again?",
            "Tic Tac Toe is Fun Fun Fun",
            JOptionPane.YES_NO_OPTION);
        frame.dispose();
        return response == JOptionPane.YES_OPTION;
    }

    /**
     * Runs the client as an application.
     */
    public static void main(String[] args) throws Exception {
        while (true) {
            String serverAddress = (args.length == 0) ? "localhost" : args[1];
            MtgTestRunsClient client = new MtgTestRunsClient(serverAddress);
            client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            client.frame.setExtendedState(client.frame.getExtendedState()|JFrame.MAXIMIZED_BOTH);
            client.frame.setVisible(true);
            client.frame.repaint();
            client.play();
            if (!client.wantsToPlayAgain()) {
                break;
            }
        }
    }
}

Here is my server code:

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;

/** * A server for a network multi-player tic tac toe game. Modified and * extended from the class presented in Deitel and Deitel "Java How to * Program" book. I made a bunch of enhancements and rewrote large sections * of the code. The main change is instead of passing data between the * client and server, I made a TTTP (tic tac toe protocol) which is totally * plain text, so you can test the game with Telnet (always a good idea.) * The strings that are sent in TTTP are: * * Client -> Server Server -> Client * ---------------- ---------------- * MOVE (0 <= n <= 8) WELCOME (char in {X, O}) * QUIT VALID_MOVE * OTHER_PLAYER_MOVED * VICTORY * DEFEAT * TIE * MESSAGE * * A second change is that it allows an unlimited number of pairs of * players to play. */ public class MtgTestRunsServer {

/**
 * Runs the application. Pairs up clients that connect.
 */
public static void main(String[] args) throws Exception {
    ServerSocket listener = new ServerSocket(8901);
    System.out.println("MTG Test Runs Server is Running");
    try {
        while (true) {
            Game game = new Game();
            Game.Player player1 = game.new Player(listener.accept(), '1');
            Game.Player player2 = game.new Player(listener.accept(), '2');
            player1.setOpponent(player2);
            player2.setOpponent(player1);
            game.currentPlayer = player1;
            player1.start();
            player2.start();
        }
    } finally {
        listener.close();
    }
}

}

/** * A two-player game. */ class Game {

Player currentPlayer;

public synchronized boolean legalMove(Player player, String move) {
    if (player == currentPlayer ) {
        currentPlayer = currentPlayer.opponent;
        currentPlayer.otherPlayerMoved(move);
        return true;
    }
    return false;
}

class Player extends Thread {
    char playerNo;
    Player opponent;
    Socket socket;
    //BufferedReader input;
    //PrintWriter output;
    ObjectInputStream input;
    ObjectOutputStream output;

    public Player(Socket socket, char playerNumber) {
        this.socket = socket;
        this.playerNo = playerNumber;
        try {
            //input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //output = new PrintWriter(socket.getOutputStream(), true);
            output = new ObjectOutputStream(socket.getOutputStream());
            output.writeObject("WELCOME " + playerNumber);
            output.flush();
            output.writeObject("MESSAGE Waiting for opponent to connect");
            output.flush();
            **input = new ObjectInputStream(socket.getInputStream());** // Must do this after constructed ObjectOutputStream above
            //output.println("WELCOME " + playerNumber);
        } catch (IOException e) {
            System.out.println("Player died: " + e);
        }
    }

    /**
     * Accepts notification of who the opponent is.
     */
    public void setOpponent(Player opponent) {
        this.opponent = opponent;
    }

    /**
     * Handles the otherPlayerMoved message.
     */
    public void otherPlayerMoved(String move) {
        //output.println("OPPONENT_MOVED " + move);
        try {
            output.writeObject("OPPONENT_MOVED " + move);
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * The run method of this thread.
     */
    public void run() {
        try {
            // The thread is only started after everyone connects.
            //output.println("MESSAGE All players connected");
            output.writeObject("MESSAGE All players connected");
            output.flush();

            // Tell the first player that it is her turn.
            if (playerNo == '1') {
                //output.println("MESSAGE Your move");
                output.writeObject("MESSAGE Your move");
                output.flush();
            }

            // Repeatedly get commands from the client and process them.
            while (true) {
                //String command = input.readLine();
                Object command;
                try {
                    command = input.readObject();
                    if(command instanceof String){
                        if (((String)command).startsWith("MOVE")) {
                            String move = ((String)command).substring(5);
                            if (legalMove(this, move)) {
                                //output.println("VALID_MOVE");
                                output.writeObject("VALID_MOVE");
                            } else {
                                output.writeObject("MESSAGE INVALID_MOVE");
                                //output.println("MESSAGE INVALID_MOVE");
                            }
                        } else if (((String)command).startsWith("QUIT")) {
                            return;
                        }
                    }
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            System.out.println("Player died: " + e);
        } finally {
            try {socket.close();} catch (IOException e) {}
        }
    }
}

}

0

2 Answers 2

1

Straight from the javadoc:

Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks but what is the corresponding ObjectOutputStream?
If the client reads from an ObjectInputStream, then the server should write to an ObjectOutputStream. That is the "corresponding" OutputStream.
If I understand correctly, a Player talks with another Player. But both start by opening an ObjectInputStream and thus blocking until the other has sent the header. So you have a deadlock: each player is waiting for the other one. One player must start by writing, and the other must start by reading. like in a phone call. If you phone a friend and you and your friend don't say anything until the other one says something, it will be a long, silent conversation :)
Kinda, updated with latest client and server code. I tried what you said and I got it past the creating the ObjectOutputStream but then the second client hung ... maybe I just need to put the ObjectInputStream constructor call after I send output.
Yes, you need to do that, since creating an ObjectInputStream starts reading and blocking immediately.
1

You need to construct the a ObjectOutputStream before the ObjectInputStream. Otherwise you get a deadlock because of the stream header written and read by the constructors.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.