我有一个关于使用服务器-客户端模型在网络中等待消息的问题。
您可以将收到的消息区分为两种不同的类型:
Ad-hoc 消息,例如“用户已登录”,与客户端中的任何其他内容无关。
响应消息,例如当您自己尝试登录时。
我的问题是关于后者,即我使用这个方案:
向服务器发送登录请求(以“登录用户名密码加密”的形式)
(客户端)等到服务器响应或发生五秒超时。
(服务器)以“loginconfirmed”或“logindenied”响应。
所以我想知道最好的编码方式是什么,我这里有一些旧代码,但我认为这里的耦合太高了,我已经围绕这段代码重写了部分框架(它也驻留在图形中类,这根本没有意义,我不应该这样做):
public void initLoginPanel() {
setLoginStatus(LoginStatus.TIMEOUT); //standard value
LoginPanelOld loginPanel = new LoginPanelOld();
int result = JOptionPane.showConfirmDialog(this, loginPanel, "Please log in", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
String login = loginPanel.getLoginValue();
if (!login.isEmpty() && login.split(" ").length == 1) {
Network.getInstance().waitFor("loginconfirmed");
Network.getInstance().waitFor("logindenied");
Network.getInstance().send("login " + login);
initSimpleTextPanel("Logging in...");
try {
//TODO synchronize on some "login waiter object"
synchronized(this) {
wait();
}
switch (loginStatus) {
case CONFIRMED:
JOptionPane.showMessageDialog(this, "Login succesful.");
break;
case DENIED:
JOptionPane.showMessageDialog(this, "Login denied.");
initLoginPanel();
break;
case TIMEOUT:
JOptionPane.showMessageDialog(this, "Could not connect to the server.");
initLoginPanel();
break;
default:
JOptionPane.showMessageDialog(this, "An unexpected error has occured.");
initLoginPanel();
break;
}
removeAll();
revalidate();
repaint();
} catch (InterruptedException ex) {
Logger.getLogger(MainPanelOld.class.getName()).log(Level.SEVERE, null, ex);
}
}
else {
JOptionPane.showMessageDialog(this, "You have entered invalid details.");
initLoginPanel();
}
}
else if (result == JOptionPane.CANCEL_OPTION || result == JOptionPane.CLOSED_OPTION) {
initLoginPanel();
}
}
我使用同步,但我不太喜欢它,所以如果可能的话,我想避免它。然而问题在于网络在不同的线程中运行,并且响应可以随时出现,但是登录过程只有五秒钟需要响应。
无需联网的重写代码:
public class LoginProcedure implements Procedure {
private final GUI gui;
private LoginPanel loginPanel;
public LoginProcedure(final GUI gui) {
this.gui = gui;
}
@Override
public void start() {
loginPanel = new LoginPanel(this);
gui.setPanel(loginPanel);
}
@Override
public void finish() {
Controller.getInstance().finishProcedure();
}
public void tryLogin(final String username, final char[] password) {
if (username.isEmpty()) {
loginPanel.setErrorMessage("Please enter your username.");
return;
}
if (password.length == 0) {
loginPanel.setErrorMessage("Please enter your password.");
return;
}
gui.setPanel(new LoadingPanel());
}
}
在新代码中,它应该从gui.setPanel(new LoadingPanel());
.
因此,再次重复主要问题:如何使 Networking 类(从服务器读取响应并处理它们的类)仅在给定时刻的给定超时内对“loginconfirmed”和“logindenied”做出反应,并重定向给定 LoginProcedure 对象的事件?