java - 为什么我的 Java 客户端/服务器应用程序在使用 ObjectInputStream 时会挂起,但在将 BufferedReader 与 InputStreamReader 结合使用时却不会挂起?

标签 java sockets

我想知道为什么它会卡在以下行,但当我将 BufferedReader 与 InputStreamReader 一起使用时,它并没有卡住:

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

这是我的客户端代码:

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;
            }
        }
    }
}

这是我的服务器代码:

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

/** * 网络多人井字游戏的服务器。修改后的和 * 扩展自 Deitel 和 Deitel“Java How to *程序”书。我做了很多改进并重写了大部分内容 * 的代码。主要的变化是在之间传递数据 * 客户端和服务器,我做了一个TTTP(井字游戏协议(protocol)),这完全是 * 纯文本,这样您就可以使用 Telnet 测试游戏(总是一个好主意。) * TTTP 中发送的字符串是: * * 客户端->服务器服务器->客户端 * ---------------- ---------------- * MOVE (0 <= n <= 8) WELCOME ({X, O} 中的字符) * 退出有效移动 * OTHER_PLAYER_MOVED * 胜利 * 打败 * 领带 * 信息 * * 第二个变化是它允许无限数量的配对 * 玩家进行游戏。 */ 公共(public)类 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();
    }
}

}

/** * 两人游戏。 */ 类游戏{

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) {}
        }
    }
}

}

最佳答案

直接来自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.

关于java - 为什么我的 Java 客户端/服务器应用程序在使用 ObjectInputStream 时会挂起,但在将 BufferedReader 与 InputStreamReader 结合使用时却不会挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20716993/

相关文章:

linux - 套接字无法检测到断开连接

c - 连续运行服务器套接字

java - 如何修复检查 Scanner 是否有另一行输入的循环?

java - 两个 Fragment 永远不应该直接通信

Java读取和编码大型二进制文件

java - 如何在 Java 中将 JavaScript 日期转换为日期?

java - 使用多个服务或在单个服务中执行所有操作哪个更好?

python - Cv2 :problem recieving full data from socket

java - bukkit 插件内的套接字在使用后关闭

Java - 在当前程序窗口之外获取选定的文本