在Runnable线程类之外访问从服务器到客户端的传递值

时间:2017-11-25 20:33:57

标签: java mysql multithreading swing client-server

我用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,第二次再次返回null(run()中的消息取值)&当我第三次点击按钮时,它会返回所需的值。

  1. 为什么它最初没有工作?
  2. 这是正确的&从服务器&amp ;;接收查询结果的正确方法在客户端上使用它?

1 个答案:

答案 0 :(得分:1)

  

为什么它最初不起作用?

您正在通过客户端向服务器发送查询,然后从数据库中提取数据,然后将其发送回客户端。这永远不会立即发生,你不应该期望它瞬间发生。您需要重新连线并重新考虑如何从服务器获取信息。

  

这是正确的&从服务器&amp ;;接收查询结果的正确方法在客户端使用它?

没有一种正确的方式,但应遵循一些通用规则。了解服务器将异步回复您的查询 - 也就是说,它不会立即发生,当发生时,您将无法确切地知道,并且它将在不同的线程上发生。因此,您的解决方案也需要异步。

由于这似乎是一个Swing GUI,如果这是我的应用程序,我就不会有这样的行:

lbl_clientStatus.setText(sharedInputFromServer);

在用于向服务器发送查询的相同代码中,因为此代码假定立即响应,并且可能是您在线性控制台程序中使用的代码,但不是您应该在事件驱动的GUI中使用的代码必须等待服务器响应。相反,再次假设这是Swing,我将我的监听器代码放在SwingWorker<Void, String>中,并且我将使用worker的发布/进程方法对来允许数据异步更新客户端GUI,何时它是可用。另一个选择是使用SwingWorker<Void, Void>并通过向worker添加PropertyChangeListener并监听双方同意的属性来监听更改。这些方法的优点在于,对于两者,客户端GUI将在其状态发生变化时由工作人员通知,并且可以相应地响应,并且还将在Swing事件线程上进行所有Swing GUI更改,从而避免混乱的并发异常。请查看本教程了解详细信息:

Lesson: Concurrency in Swing

例如,假设您的客户端GUI名为SimpleClientGui,并且说它有一个名为outputTextArea的JTextArea,以及一个允许外部类将文本附加到文本区域的公共方法:

public class SimpleClientGui extends JPanel {

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

    // ...

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

您可以创建一个名为ServerListener的SwingWorker,它在Swing事件线程上调用上面的appendToOutput方法,如下所示:

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