我正在尝试编写一个非常简单的客户端 - 服务器程序。
基本上,只要客户端连接到服务器,他就会获得一个登录屏幕,他必须输入用户名密码和文件名。
我的问题是:
这是客户端的代码:
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方法之前,如何让客户端等待我实际点击登录按钮?我该如何修复连接重置错误?
答案 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获取输入值。