简体   繁体   English

为什么我的Java客户端/服务器应用程序在使用ObjectInputStream时挂起但在我使用带有InputStreamReader的BufferedReader时却没有?

[英]Why does my Java client/server app hang when using ObjectInputStream but doesn't when I use BufferedReader with InputStreamReader?

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: 我想知道为什么它会卡在下面这一行,但是当我使用带有InputStreamReader的BufferedReader时它不会被卡住:

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.BufferedReader; import java.io.IOException; import java.io.IOException; import java.io.InputStreamReader; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectOutputStream; import java.io.PrintWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.ServerSocket; import java.net.Socket; import java.net.Socket;

/** * A server for a network multi-player tic tac toe game. / ** *用于网络多玩家tic tac toe游戏的服务器。 Modified and * extended from the class presented in Deitel and Deitel "Java How to * Program" book. 修改和*扩展Deitel和Deitel“Java How to * Program”一书中提供的类。 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. 主要的变化是不是在*客户端和服务器之间传递数据 ,而是制作了一个完全*纯文本的TTTP(tic tac toe协议),所以你可以用Telnet测试游戏(总是一个好主意。)*字符串在TTTP中发送的是:* *客户端 - >服务器服务器 - >客户端* ---------------- ---------------- * MOVE(0 <= n <= 8)WELCOME({X,O}中的字符} * QUIT VALID_MOVE * OTHER_PLAYER_MOVED * VICTORY * DEFEAT * TIE * MESSAGE * *第二个变化是它允许无限数量的*对*玩家玩。 */ public class MtgTestRunsServer { * / 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) {}
        }
    }
}

} }

Straight from the javadoc : 直接来自javadoc

Creates an ObjectInputStream that reads from the specified InputStream. 创建一个从指定的InputStream读取的ObjectInputStream。 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. 此构造函数将阻塞,直到相应的ObjectOutputStream已写入并刷新标头。

You need to construct the a ObjectOutputStream before the ObjectInputStream. 您需要在ObjectInputStream 之前构造一个ObjectOutputStream。 Otherwise you get a deadlock because of the stream header written and read by the constructors. 否则,由于构造函数编写并读取了流标头,因此会出现死锁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 尝试使用ImageIO时,为什么Mac上会挂起Java? - Why does Java hang on my Mac when I try to use ImageIO? 使用ObjectInputStream而不是BufferedReader时获取NullPointerException - Get NullPointerException when using ObjectInputStream instead of BufferedReader 使用C客户端和Java服务器时,BufferedReader readLine仍然被阻止 - BufferedReader readLine remains blocked when using C client and Java server 读取所有字符时,是否有理由在InputStreamReader上使用BufferedReader? - Is there a reason to use BufferedReader over InputStreamReader when reading all characters? 在 Java 中使用 InputStreamReader class 时缺少字符 - Character missing when use the InputStreamReader class in Java 当我的代码不使用 ArrayLIst 时,为什么 ArrayList.java 会出现 NullPointerException 错误? - Why does a NullPointerException error appear for ArrayList.java when my code doesn't use an ArrayLIst? 在Java中嵌入CPython时,为什么会挂起? - When embedding CPython in Java, why does this hang? Java中的BufferedReader和InputStreamReader - BufferedReader and InputStreamReader in Java 我什么时候应该使用InputStreamReader和OutputStreamWriter? - When should I use InputStreamReader and OutputStreamWriter? 在Java中,即使文件存在(并且已使用java确认存在),BufferedReader也找不到文件! - In java BufferedReader doesn't find a file, even when file exists (and it's existance is confirmed using java)!
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM