服务器 - 客户端模型中的Java网络

时间:2013-05-03 20:31:18

标签: java client-server

我有一个关于使用服务器 - 客户端模型在网络中等待消息的问题。

您可以用两种不同的类型区分收到的消息:

  1. 特殊消息,例如“用户已登录”,与客户端中的任何其他内容无关。

  2. 响应消息,例如当您自己尝试登录时。

  3. 我的问题是关于后者,即我使用这个方案:

    1. 向服务器发送登录请求(以“登录用户名密码加密”的形式)

    2. (客户端)等到服务器响应或发生超时5秒。

    3. (服务器)使用“loginconfirmed”或“logindenied”回复。

    4. 所以我想知道什么是最好的代码编码方式,我这里有一些旧代码,但我认为这里的耦合太高了,我已经围绕这段代码重写了部分框架(它也驻留在在图形类中,根本没有意义,我不应该这样做):

      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对象?

1 个答案:

答案 0 :(得分:0)

我会以启用同步/异步消息系统的方式设计它。

  • 每条可交换消息都必须具有UUID和'originID'属性。
  • 只需从发射器向接收器发送异步消息。
  • 同步消息将其内容发送到接收方,并进入“等待回复”队列。调用者线程暂停,或者不时地对队列进行ping操作。
  • 接收方解析原始邮件,准备回复并使用原始邮件的ID填充originID属性。
  • 回复消息将发送到发射器。
  • 发射器解析它,识别它是一个回复,并发出“等待回复”队列的信号。
  • 允许原始主题继续进行,并附上回复。
  • 如果没有回复,则可能会引发TimeOutException。