2016-04-28 31 views
0

IM在JavaFX的工作UI。我創建了一個echo ServerClient系統,即將數據發送到服務器並返回到所有客戶端(廣播)。它在客戶端向服務器發送數據時工作正常。但是,當服務器將數據發送回客戶端時,該幀會凍結。下面是代碼: 客戶:的BufferedReader凍結在JavaFX

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package com.rajeshpatkar; 

import java.io.BufferedReader; 
import java.io.BufferedWriter; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.Socket; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.application.Application; 
import static javafx.application.Application.launch; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TextArea; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

/** 
* 
* @author Dimpi 
*/ 
public class Client extends Application{ 

    int flag = 999; 


    public void start(Stage primaryStage) throws Exception { 

     Connect cnn = new Connect(primaryStage); 
     cnn.sconnect(); 

    } 

    public static TextArea Frame(Stage primaryStage, PrintWriter nos, BufferedReader nis) throws IOException { 

     TextField tf = new TextField(); 
     TextArea ta = new TextArea(); 
     Button btn = new Button(); 
     btn.setText("Click"); 
     btn.setOnAction(new EventHandler<ActionEvent>() { 

      @Override 
      public void handle(ActionEvent event) { 

       String get = tf.getText(); 
       nos.println(get); 
       try { 
        Connect.chat(nis,ta); 
       } catch (IOException ex) { 
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex); 
       } 

      } 
     }); 

     BorderPane root = new BorderPane(); 
     root.setCenter(ta); 
     BorderPane panel = new BorderPane(); 
     root.setBottom(panel); 
     panel.setCenter(tf); 
     panel.setRight(btn); 
     Scene scene = new Scene(root, 300, 250); 

     primaryStage.setTitle("Hello World!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
     return ta; 

    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 

} 

class Connect { 

    Stage primaryStage; 

    Connect(Stage primaryStage) { 
     this.primaryStage = primaryStage; 
    } 

    public void sconnect() throws IOException { 
     System.out.println("Client Signing IN"); 
     Socket soc = new Socket("localhost", 9081); 
     PrintWriter nos = new PrintWriter(
       new BufferedWriter(
         new OutputStreamWriter(soc.getOutputStream() 
         ) 
       ), true); 
     BufferedReader nis = new BufferedReader(
       new InputStreamReader(soc.getInputStream() 
       ) 
     ); 

     TextArea ta=Client.Frame(primaryStage, nos, nis); 

    } 

    public static void chat(BufferedReader nis,TextArea ta) throws IOException{ 

     String set = nis.readLine(); 

     while (!set.equals("End")) { 
      ta.appendText(set+"\n"); 
      set = nis.readLine(); 

     } 
    } 
} 


Server: /* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package com.rajeshpatkar; 

import static com.rajeshpatkar.Server.a1; 
import java.io.BufferedReader; 
import java.io.BufferedWriter; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 
import javafx.application.Application; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

/** 
* 
* @author Dimpi 
*/ 
public class Server extends Application { 
    public static ArrayList<PrintWriter> a1=new ArrayList<PrintWriter>(); 

    @Override 
    public void start(Stage primaryStage) throws IOException { 

     System.out.println("Server signing IN"); 
     ServerSocket ss = new ServerSocket(9081); 
     for (int i = 0; i < 5; i++) { 
      Socket soc = ss.accept(); 
      Conversation c = new Conversation(soc); 
      c.start(); 
     } 

    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 

} 

class Conversation extends Thread { 

    Socket soc; 

    Conversation(Socket soc) { 
     this.soc = soc; 
    } 

    public void run() { 
     try { 

      PrintWriter nos = new PrintWriter(
        new BufferedWriter(
          new OutputStreamWriter(soc.getOutputStream() 
          ) 
        ), true); 
      BufferedReader nis = new BufferedReader(
        new InputStreamReader(soc.getInputStream() 
        ) 
      ); 
      Server.a1.add(nos); 
      String get=nis.readLine(); 
      while(true){ 
       for(PrintWriter p:a1){ 
      System.out.println(get); 

      p.println(get); 
       } 
      get=nis.readLine(); 
      } 

     } catch (Exception e) { 

     } 

    } 
} 
+0

可能長時間運行的任務(例如採取可能需要幾秒鐘的連接),應該從JavaFX的幽後臺線程來完成應用線程。檢查[this](https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm)鏈接如何執行此操作。如果你已經實現了這個邏輯,你的應用程序不會凍結。 –

回答

0

凍結客戶端的UI的問題導致你的方法:chat()。這由你的按鈕調用。它包含方法readLine()BufferedReader,它將等待輸入發生。此等待將導致您的凍結,因爲它發生在應用程序線程上。

所以你可以做的是:在你的按鈕事件處理程序:寫輸出:

String get = tf.getText(); 
nos.println(get); 

但增加了一個線程,如果你的InputStream接收輸入,將更新文本區,例如像這樣:

static void handleInput(BufferedReader nis, TextArea ta) throws IOException { 

    final Task<Void> task = new Task<Void>() { 
     @Override 
     protected Void call() throws Exception { 
      String output; 
      while ((output = nis.readLine()) != null) { 
       final String value = output; 
       Platform.runLater(new Runnable() { 

        @Override 
        public void run() { 
         ta.appendText(value + System.getProperty("line.separator")); 
        } 
       }); 
      } 
      return null; 
     } 
    }; 
    new Thread(task).start(); 
} 

,並調用該方法一次:

handleInput(nis, ta);