我有一個關於在使用服務器 - 客戶端模型的網絡中等待消息的問題。服務器 - 客戶端模型中的Java網絡
您可以用兩種不同類型的區分接收到的消息:
特設消息,例如「用戶登錄」,這不涉及到在客戶端什麼都重要。 。
響應性消息,例如,當你自己嘗試登錄
我的問題是關於後者,也就是我用這個方案:
發送登錄請求服務器(以「登錄用戶名密碼加密」的形式)
(客戶端)等到服務器響應或者直到超時五秒發生。
(服務器)通過「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();
}
}
我使用同步,但我真的不喜歡它,所以如果可能的話我會想避免它。 然而,問題的類型是網絡運行在不同的線程中,並且響應可以隨時進行,但是登錄過程只需要5秒鐘就可以響應。
重寫代碼,無需聯網:
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());
後,網絡開始。
所以再一次重複主要問題:如何使網絡類(讀取來自服務器的響應並處理它們的類)僅在給定的超時時間內對給定的超時給予「loginconfirmed」和「logindenied」時刻,並將事件重定向到給定的LoginProcedure對象?