让客户端等待输入,客户端 - 服务器

时间:2016-06-03 16:52:19

标签: java user-interface server client

我正在尝试编写一个非常简单的客户端 - 服务器程序。

基本上,只要客户端连接到服务器,他就会获得一个登录屏幕,他必须输入用户名密码和文件名。

我的问题是:

  1. 客户端继续执行代码流而不实际等待输入。
  2. 服务器端似乎卡在某条线路上,我重置连接。
  3. 这是客户端的代码:

    public static void main(java.lang.String[] args) throws JsonIOException, JsonSyntaxException, ClassNotFoundException, IOException
    {
        try
        {
            Socket socket = new Socket(InetAddress.getLocalHost(), 12345);
            LoginScreen login = new LoginScreen();
            login.open();
            String name = login.getUsername();
            String pass = login.getPassword();
            String log = login.getLogname();
            System.out.println(name + " " + pass + " " + log);
        }
    

    这是LoginScreen

    @SuppressWarnings("serial")
    public class LoginScreen extends JFrame implements ActionListener
    {
        private JTextField userText;
        private JTextField passText;
        private JTextField logText;
        private JLabel userLabel;
        private JLabel passLabel;
        private JLabel logLabel;
        private JButton loginButton;
    
        private String username;
        private String password;
        private String logname;
    
        public String getUsername()
        {
            return username;
        }
    
        public String getPassword()
        {
            return password;
        }
    
        public String getLogname()
        {
            return logname;
        }
    
        public LoginScreen()
        {
            super("Login");
    
            userLabel = new JLabel("username: ");
            passLabel = new JLabel("password: ");
            logLabel = new JLabel("File name: ");
    
            Dimension preferredSize = new Dimension(80,20);
            userText = new JTextField("");
            userText.setPreferredSize(preferredSize);
            passText = new JTextField("");
            passText.setPreferredSize(preferredSize);
            logText = new JTextField("");
            logText.setPreferredSize(preferredSize);
    
            loginButton = new JButton("Login");
            loginButton.addActionListener(this);
        }
        public void open()
        {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(500,500);
            setLayout(new BorderLayout());
    
            JPanel userPanel = new JPanel();
            userPanel.setLayout(new FlowLayout());
            add(userPanel,BorderLayout.NORTH);
    
            JPanel passPanel = new JPanel();
            passPanel.setLayout(new FlowLayout());
            add(passPanel,BorderLayout.CENTER);
    
            JPanel logPanel = new JPanel();
            logPanel.setLayout(new FlowLayout());
            add(logPanel,BorderLayout.SOUTH);
    
            JPanel loginPanel = new JPanel();
            loginPanel.setLayout(new FlowLayout());
            add(loginPanel,BorderLayout.EAST);
    
            userPanel.add(userLabel);
            userPanel.add(userText);
            passPanel.add(passLabel);
            passPanel.add(passText);
            logPanel.add(logLabel);
            logPanel.add(logText);
            loginPanel.add(loginButton);
    
            pack();
    
            this.setVisible(true);
        }
        @Override
        public void actionPerformed(ActionEvent arg0) 
        {
            username = new String(userText.getText());
            password = new String(passText.getText());
            logname = new String(logText.getText());
        }
    }
    

    这是服务器

    try 
    {
        Socket client = socket.accept();
        ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
        ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
        String userPassFile = (String)ois.readObject();
        String[] parts = userPassFile.split("");
        if(AuthenticationManager.Authenticate(parts[0], parts[1]))
        {
            new MMULogService(client,parts[2]);
        }
        else
        {
            oos.writeObject("Incorrect Username / Password");
        }
        client.close();
    } 
    

    应该注意的是,在执行客户端之前,我打开服务器。 目前输出为null null null IE - 客户端在登录屏幕上单击“登录”之前到达login.getUsername方法。

    一旦我关闭登录屏幕,我就会收到错误 -

    java.net.SocketException:在服务器的第ObjectInputStream ois = new ObjectInputStream(client.getInputStream());行重置连接。

    在执行get方法之前,如何让客户端等待我实际点击登录按钮?我该如何修复连接重置错误?

1 个答案:

答案 0 :(得分:1)

以下是解决第一个问题的方法(对于第二个问题,我没有看到您的代码,因此我无法提供帮助),您需要一种方法来同步主线程和UI。

首先让AWT event dispatching thread启动你的用户界面:

SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        login.open();
    }
});

或者如果您使用Java 8,只需:

SwingUtilities.invokeLater(() -> login.open());

然后让主线程在get方法之前等待,方法是调用这样的新方法:

login.waitForInputs();
String name = login.getUsername();
...

然后在你的班级LoginScreen中,新方法只会让调用线程等待:

public void waitForInputs() throws InterruptedException {
    synchronized (this) {
        // Make the current thread waits until a notify or an interrupt
        wait();
    }
}

最后,您需要修改方法actionPerformed,以便在可行时释放主线程,方法如下:

public void actionPerformed(ActionEvent arg0)
{
    username = userText.getText();
    password = passText.getText();
    logname = logText.getText();
    // Here you should test if the input values are OK if it is KO do a   
    // return to prevent calling the following code
    synchronized (this) {
        // Release the waiting threads
        notifyAll();
    }
}

完成后我们已经实现了一个简单的wait/notify机制,在调用get方法之前从UI获取输入值。