2017-11-25 130 views
-2

我正在用Java寫一個客戶端 - 服務器桌面應用程序。我寫了一個運行的服務器(打開套接字)&等待客戶端連接。客戶端不直接與數據庫(MySQL)通信,他們向服務器發送查詢,服務器執行查詢&將結果集轉換爲JSON &將其發送回客戶端。 在客戶端我寫一個Listener類:訪問從服務器到客戶端以外的傳遞值可運行線程類

private class Listner implements Runnable { 
    private Thread t; 
    private final Socket socket; 
    private BufferedReader input; 

    Listner(Socket s) { 
     socket = s; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       String message; 
       message = input.readLine(); 
       sharedInputFromServer = input.readLine(); 
       System.out.println("message value in run(): " + message); 
      } catch (IOException e) { 

      } 

      try { 
       Thread.sleep(30); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(ClientDashboard.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 

    public void start() { 
     try { 
      input = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
      System.out.println("input value in start() :" + input); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     if (t == null) { 
      t = new Thread (this, "client"); 
      t.start(); 
     } 
    } 
} 

在客戶機GUI使用返回的數據,我限定的可變

public String sharedInputFromServer; 

和用於測試我設置的actionPerformed一個按鈕來更新標籤有返回值

private void btn_sendToServerActionPerformed(java.awt.event.ActionEvent evt) {             
    if (null != output) { 
     String textToSend = "SELECT unit_id, unit_name FROM units;"; 
     output.println(textToSend); 
     System.out.println("got the share: " + sharedInputFromServer); 
     lbl_clientStatus.setText(sharedInputFromServer); 
    } 

當我點擊鏈接首次sharedInputFromServer返回null,第二次它再次返回空值(消息在運行()取值)&當我第三次點擊按鈕時,它返回所需的值。

  1. 爲什麼它一開始不工作?
  2. 這是正確的&從服務器接收查詢結果的正確方法&在客戶端上使用它嗎?
+0

其他問題:我會避免將Thread對象**放入** Runnable中。讓調用代碼成爲啓動並控制線程對象本身的代碼。 –

+0

請參閱編輯 –

+0

.......... hello? –

回答

1

爲何起初不工作?

您正在通過客戶端向服務器發送查詢,然後從數據庫中提取數據,然後將其發送回客戶端。這絕不會發生瞬間,你不應該期望它瞬間發生。您需要重新連線並重新考慮如何從服務器獲取信息。

這是從服務器接收&查詢結果使用它的客戶的權利&正確方法?

沒有單一的正確的的方式,但有一些應遵循的一般規則。瞭解服務器將異步回覆您的查詢 - 也就是說,它不會立即發生,您將無法確切知道何時會發生,並且它將發生在不同的線程上。所以你的解決方案也需要異步。

因爲這似乎是一個Swing GUI,如果這是我的申請,我不會有一個線,如:

lbl_clientStatus.setText(sharedInputFromServer); 
中使用的查詢發送到服務器相同的代碼

,因爲此代碼假定立即作出響應,並且可能是您在線性控制檯程序中使用的代碼,但不是您應該在必須等待服務器響應的事件驅動的GUI中使用的代碼。相反,再次假設這是Swing,我將我的偵聽器代碼放在SwingWorker<Void, String>之內,我使用工作者的發佈/處理方法對來允許數據異步更新客戶端GUI,以及何時可用。另一個選擇是使用SwingWorker<Void, Void>並通過向工作人員添加PropertyChangeListener並監聽相互同意的屬性來監聽更改。這些方法的優點是,對於這兩種情況,客戶端GUI將在其狀態發生變化時通知工作人員,並且可以做出相應響應,並且所有Swing GUI更改都將在Swing事件線程上進行,從而避免混亂的併發異常。獲取詳細信息請查看本教程:

Lesson: Concurrency in Swing


例如,假設您的客戶端GUI被稱爲SimpleClientGui,並說,它有一個JTextArea叫outputTextArea,並允許外部類的公共方法

public class SimpleClientGui extends JPanel { 

    // ... 
    private JTextArea outputTextArea = new JTextArea(25, 50); 

    // ... 

    public void appendToOutput(String text) { 
     outputTextArea.append(text); 
    } 

您可以創建一個SwingWorker的,說叫ServerListener,調用上述appendToOutput方法在Swing事件THR:將文本追加到文本區的能力ead,如下所示:

import java.io.InputStream; 
import java.util.List; 
import java.util.Scanner; 
import javax.swing.SwingWorker; 

public class ServerListener extends SwingWorker<Void, String> { 
    private SimpleClientGui simpleClient; 
    private Scanner scanner; 

    public ServerListener(SimpleClientGui simpleClient, InputStream inputStream) { 
     this.simpleClient = simpleClient; 
     this.scanner = new Scanner(inputStream); 
    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     while (scanner.hasNextLine()) { 
      // push the next line to the process method 
      publish(scanner.nextLine()); 
     } 
     if (scanner != null) { 
      scanner.close(); 
     } 
     return null; 
    } 

    @Override 
    protected void process(List<String> chunks) { 
     for (String chunk : chunks) { 
      // this is called on the Swing event thread 
      simpleClient.appendToOutput(chunk + "\n"); 
     } 
    } 
} 
相關問題