使服务器等待来自两个不同控制器的输入

时间:2018-12-04 13:13:29

标签: java sockets javafx server

我制作了一个客户端服务器应用程序,其中服务器必须向客户端发送电子邮件列表,该电子邮件列表在加载到ListView之后,可以通过menuBar删除它们。在客户端,所有这些操作都是在数据模型中进行的(我遵循MVC模式)。这是服务器:

class ThreadedEchoHandler implements Runnable {

    private Socket incoming;

    private String nomeAccount = "";

    public void run() {
        try {
            incoming = s.accept();
        } catch (IOException ex) {
            System.out.println("Unable to accept requests");
        }
        contenutoTextArea.append("Connected from: " + incoming.getLocalAddress() + "\n");
        textarea.setText(contenutoTextArea.toString());
        try {
            //PHASE 1: The server receives the email
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
                nomeAccount = in.readLine();
            } catch (IOException ex) {
                System.out.println("Not works");
            }

            //PHASE 2: I'm getting all the emails from the files
            File dir = new File("src/server/" + nomeAccount);
            String[] tmp = new String[100];
            int i = 0;
            for (File file : dir.listFiles()) {
                if (file.isFile() && !(file.getName().equals(".DS_Store"))) {
                    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                        String line;
                        while ((line = br.readLine()) != null) {
                            tmp[i++] = line;
                        }
                    } catch (IOException ex) {
                        System.out.println("Cannot read from file");
                    }
                }
            }

            //PHASE 3: The server sends the ArrayList to the client
            PrintWriter out = new PrintWriter(incoming.getOutputStream(), true);
            for (int j = 0; j < i; j++) {
                out.println(tmp[j]); // send the strings to the client
            }
        } catch (IOException ex) {
            System.out.println("Cannot send the strings to the client");
        }

        //PHASE 4: Here I loop and wait for the client choise
        BufferedReader in;
        String op;
        try {
            in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
            while ((op = in.readLine()) != null) {                   
                if (op.equals("Elimina")) {
                    String tmp = in.readLine();
                    File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
                    file.delete();
                } else if (op.equals("Invia")) {
                    //...
                } else {
                    //...
                }
            }
        } catch (IOException ex) {
            System.out.println("Non so");

        } finally {
            try {
                incoming.close();
            } catch (IOException ex) {
                System.out.println("Cannot closing the socket");
            }
        }
    }
}

这些是客户端的方法:

public void loadData() throws IOException, ClassNotFoundException, ParseException {

    try {
        s = new Socket("127.0.0.1", 5000);
        ArrayList<Email> email = new ArrayList<Email>();
        DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        Date data;

        /* PHASE 1: The client sends a string to the server */
        //try {
            PrintWriter out = new PrintWriter(s.getOutputStream(), true);
            out.println(account); // send the account name to server

            /* PHASE 2: The client receives the ArrayList with the emails */
            BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line;
            String message[] = new String[5];
            for (int j=0; (line = in.readLine()) != null;) {
                message[j++] = line;
                if (j==5) {
                    data = format.parse(message[3]);
                    email.add(new Email((Integer.parseInt(message[0])), message[1], account, message[2], message[4], data));
                    j=0;
                }
            }

            //Casting the arrayList
            emailList = FXCollections.observableArrayList(email);

            //Sorting the emails
            Collections.sort(emailList, (Email o1, Email o2) -> {
                if (o1.getData() == null || o2.getData() == null) {
                    return 0;
                }
                return o1.getData().compareTo(o2.getData());
            });

        /*} finally {
            s.close();*/
        //}
    } catch (SocketException se) {
        emailList.setAll(null, null);
    }
}

public void deleteMail(Email da_elim) throws IOException {
    int id_del = da_elim.getID();
    emailList.remove(da_elim);
    PrintWriter out = new PrintWriter(s.getOutputStream(), true);
    out.println("Elimina");
    out.println(id_del);
}

服务器的阶段1、2、3用于上传电子邮件,并使用loadData()方法。没有阶段4,该程序将运行。现在,如果我编写了该循环,则客户端的GUI不会加载,并且我无法按DELETE按钮(这会使输入将某些内容(在此消除了文件中)嵌入该循环中)。即使它们是两个不同的线程也不会加载?为什么没有该循环就可以工作呢?

编辑:已实现Listener类,但仍无法正常工作

//PHASE 4: Here I loop and wait for the client choise      
        BufferedReader in;
        String op;
        try {
            in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
            /*while ((op = in.readLine()) != null) {
                System.out.println("OP: " + op);
                if (op.equals("Elimina")) {
                    String tmp = in.readLine();
                    contenutoTextArea.append("Ho eliminato la mail ").append(tmp).append(" \n");
                    textarea.setText(contenutoTextArea.toString());
                    File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
                    file.delete();
                }
            }*/
            Listener lis = new Listener(in, new LinkedBlockingQueue<String>());
            lis.run();
            System.out.println("bbbbb");
        } catch (IOException ex) {
            System.out.println("Unable to read messages");
        } finally {
            try {
                incoming.close();
            } catch (IOException ex) {
                System.out.println("Cannot close the socket");
            }
        }

2 个答案:

答案 0 :(得分:2)

我认为您应该运行jvisualvm(这是在jdk的/ bin /位置中与jdk一起安装的工具),并查找您在服务器上创建的Thread生命周期。还要检查您的线程是否不执行代码,而只是跳过等待客户端的生命。

该线程是否以某种方式与客户端连接?因为您无法运行客户端应用程序。他们分开了吗?我想到的另一个想法是使用

Platform.runLater(()->{
});

如果您的客户端GUI在JavaFX中。如果要创建GUI,更改字段中的值以及在GUI上执行的任何操作,请使用它。也许您的服务器正在等待用户响应,并且在构建GUI之后?这导致您无法按DELETE按钮。

答案 1 :(得分:2)

我目前无法发表评论,因此无法要求澄清,但我认为我正确地解释了问题所在。 “程序进入等待来自两个控制器的输入的循环时挂起”。假设我理解的正确,最可能的罪魁祸首是缓冲的阅读器无限期挂起,因为它没有收到输入。当我第一次遇到此问题时,我将其扔到了自己的“接收器”类中,并使用一个队列将接收到的所有内容传递到主类中的循环中。我的代码看起来像这样:

import java.io.BufferedReader;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;

public class Listener implements Runnable
{
    private BufferedReader br;
    private BlockingQueue<String> q;
    private boolean shouldClose = false;

    public Listener(BufferedReader br, BlockingQueue<String> q)
    {
        this.q = q;
        this.br = br;
    }

    public void run()
    {
        loop();
        System.out.println("listener has stopped");
    }

    public void loop()
    {
        String line = "";

        try
        {
            while((line = br.readLine()) != null && !shouldClose)
            {
                q.put(line);
            }
        }
        catch (IOException | InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public void shutdown()
    {
        shouldClose = true;
    }
}

如果我有任何误解,或者错过了代码中的内容,我们深表歉意。