0

サーバー クライアント モデルを使用したネットワークでのメッセージの待機について質問があります。

受信したメッセージは、次の 2 つの異なるタイプで区別できます。

  1. 「ユーザーがログインしました」などのアドホック メッセージで、クライアントの他のものとは関係ありません。

  2. たとえば、自分がログインしようとしているときの応答メッセージ。

私の質問は後者に関するものです。つまり、私はこのスキームを使用しています:

  1. ログイン要求をサーバーに送信します (「ログイン ユーザー名 パスワード暗号化」の形式で)

  2. (クライアント) サーバーが応答するまで、または 5 秒のタイムアウトが発生するまで待ちます。

  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());.

もう一度主な質問を繰り返します: Networking クラス (サーバーからの応答を読み取り、それらを処理するクラス) を、特定の瞬間に特定のタイムアウトで "loginconfirmed" と "logindenied" にのみ反応させ、リダイレクトする方法を教えてください。指定された LoginProcedure オブジェクトへのイベント?

4

1 に答える 1