2013-05-03 119 views
0

我有一個關於在使用服務器 - 客戶端模型的網絡中等待消息的問題。服務器 - 客戶端模型中的Java網絡

您可以用兩種不同類型的區分接收到的消息:

  1. 特設消息,例如「用戶登錄」,這不涉及到在客戶端什麼都重要。 。

  2. 響應性消息,例如,當你自己嘗試登錄

我的問題是關於後者,也就是我用這個方案:

  1. 發送登錄請求服務器(以「登錄用戶名密碼加密」的形式)

  2. (客戶端)等到服務器響應或者直到超時五秒發生。

  3. (服務器)通過「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對象?

回答

0

我會設計它以啓用同步/異步消息系統。

  • 每個可交換消息必須具有UUID和'originID'屬性。
  • 異步消息只是從發射器發送到接收器。
  • 同步消息將其內容發送給接收方,並進入「等待回覆」隊列。呼叫者線程暫停,或者不時排隊。
  • 接收者解析原始消息,準備回覆並用原始消息的ID填充originID屬性。
  • 回覆消息發送到發射器。
  • 發射器解析它,認識到它是回覆,併發出'等待回覆'隊列的信號。
  • 允許原始線程繼續進行,並附有答覆。
  • 如果沒有回覆,則可能會引發TimeOutException。