2017-11-25 145 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"); 
     } 
    } 
} 
相关问题