2013-12-21 47 views
0

我想知道爲什麼它被卡住以下線,但它並沒有使用,當我使用一個BufferedReader使用的InputStreamReader卡住:爲什麼我的Java客戶端/服務器應用程序在使用ObjectInputStream時掛起,但是當我在InputStreamReader中使用BufferedReader時沒有掛起?

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

這是我的服務器代碼:

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;

/** *用於網絡多玩家井字棋遊戲的服務器。修改和 *擴展從Deitel和Deitel「Java如何 *程序」書中提出的類。我做了一系列增強,並且重寫了代碼的大型部分 *。主要的改變是不是通過數據之間的 *客戶端和服務器,我做了一個TTTP(井字棋協議),這是完全 *純文本,所以你可以用Telnet測試遊戲(總是一個好主意。 ) *以TTTP發送的字符串爲: * * Client - > Server Server - > Client * ---------------- -------- -------- * MOVE(0 < = N < = 8)WELCOME(炭在{X,O-}) * QUIT VALID_MOVE * OTHER_PLAYER_MOVED * VICTORY * DEFEAT * TIE * M ESSAGE * *第二個變化是它允許無限數量的玩家對玩 *玩家。 */ 公共類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) {} 
     } 
    } 
} 

}

回答

1

直從the javadoc

創建一個的ObjectInputStream從指定的InputStream讀取。從流中讀取序列化流頭並進行驗證。該構造函數將阻塞,直到相應的ObjectOutputStream寫入並刷新標題。

+0

感謝但是相應的ObjectOutputStream是什麼? –

+0

如果客戶端從ObjectInputStream中讀取,那麼服務器應該寫入ObjectOutputStream。這是「相應的」OutputStream。 –

+0

我不知道我可以在哪裏放置沖水。見上面更新。 –

1

您需要在ObjectInputStream之前構造一個ObjectOutputStream 。否則,由於構造函數寫入和讀取的流頭,會導致死鎖。

相關問題