让客户端等待输入,客户端 - 服务器
make client wait for input, client - server
我正在尝试编写一个非常简单的客户端-服务器程序。
基本上,一旦客户端连接到服务器,他就会看到一个登录屏幕,他必须在其中输入用户名密码和文件名。
我的问题是:
- 客户端继续代码流而不实际等待输入。
- 服务器端似乎卡在了某条线上,我重置了连接。
这是客户端的代码:
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);
}
这是登录界面
@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" 之前,客户端到达 login.getUsername 方法。
关闭登录屏幕后,出现错误 -
java.net.SocketException: 连接在服务器 ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
行重置。
如何让客户端在执行 get 方法之前等待我实际点击登录按钮?我该如何修复连接重置错误?
这是解决第一个问题的方法(第二个问题我没有看到您的代码,所以我无能为力),您需要一种同步主线程和 UI 的方法。
所以首先让 AWT event dispatching thread
启动您的 UI 作为下一个:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
login.open();
}
});
或者如果您使用 Java 8,只需:
SwingUtilities.invokeLater(() -> login.open());
然后让你的主线程在 get 方法之前等待,方法是让它像这样调用一个新方法:
login.waitForInputs();
String name = login.getUsername();
...
然后在您的 class 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 获取输入值。
我正在尝试编写一个非常简单的客户端-服务器程序。
基本上,一旦客户端连接到服务器,他就会看到一个登录屏幕,他必须在其中输入用户名密码和文件名。
我的问题是:
- 客户端继续代码流而不实际等待输入。
- 服务器端似乎卡在了某条线上,我重置了连接。
这是客户端的代码:
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);
}
这是登录界面
@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" 之前,客户端到达 login.getUsername 方法。
关闭登录屏幕后,出现错误 -
java.net.SocketException: 连接在服务器 ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
行重置。
如何让客户端在执行 get 方法之前等待我实际点击登录按钮?我该如何修复连接重置错误?
这是解决第一个问题的方法(第二个问题我没有看到您的代码,所以我无能为力),您需要一种同步主线程和 UI 的方法。
所以首先让 AWT event dispatching thread
启动您的 UI 作为下一个:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
login.open();
}
});
或者如果您使用 Java 8,只需:
SwingUtilities.invokeLater(() -> login.open());
然后让你的主线程在 get 方法之前等待,方法是让它像这样调用一个新方法:
login.waitForInputs();
String name = login.getUsername();
...
然后在您的 class 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 获取输入值。