代码之家  ›  专栏  ›  技术社区  ›  JimBelushi2

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

  •  -2
  • JimBelushi2  · 技术社区  · 7 年前

    我制作了一个客户机-服务器应用程序,服务器必须向客户机发送一个电子邮件列表,在将该列表加载到列表视图后,可以通过菜单栏删除它们。在客户机中,所有这些操作都是在数据模型中进行的(我遵循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()方法。没有第四阶段,这个程序就可以工作。现在,如果我编写了这个循环,客户端的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 回复  |  直到 7 年前
        1
  •  2
  •   kszulchs    7 年前

    我认为您应该运行jvisualvm(它是一个在jdk的/bin/location中安装了jdk的工具)并查找您在服务器上创建的线程生命周期。还要检查你的线程是否没有通过代码,只是结束了他的生命跳过等待客户端。

    这个线程与客户端有什么联系吗?因为你不能运行客户端应用程序。他们分开了吗?我想到的另一个想法是

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

    如果您的客户机GUI在JavaFX中。如果要创建GUI、更改字段中的值以及在GUI上执行的任何操作,请使用它。也许您的服务器正在等待用户的响应,在构建GUI之后呢?所以你不能按删除按钮。

        2
  •  2
  •   HamBone41801    7 年前

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

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

    抱歉,如果我有任何误解,或错过了你的代码。