我有一个关于使用服务器 - 客户端模型在网络中等待消息的问题。
您可以用两种不同的类型区分收到的消息:
特殊消息,例如“用户已登录”,与客户端中的任何其他内容无关。
响应消息,例如当您自己尝试登录时。
我的问题是关于后者,即我使用这个方案:
向服务器发送登录请求(以“登录用户名密码加密”的形式)
(客户端)等到服务器响应或发生超时5秒。
(服务器)使用“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对象?
答案 0 :(得分:0)
我会以启用同步/异步消息系统的方式设计它。