简体   繁体   English

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

[英]Java networking in server-client model

I have a question regarding waiting on messages in a network using a server-client model. 我有一个关于使用服务器-客户端模型在网络中等待消息的问题。

You can distinguish the received messages in two different types: 您可以将接收到的消息分为两种不同的类型:

  1. Ad-hoc messages, for example "user has logged in", which do not relate to anything else in the client. 临时消息,例如“用户已登录”,与客户端中的其他任何消息都不相关。

  2. Responsive messages, for example when you yourself are trying to log in. 响应消息,例如当您自己尝试登录时。

My question is about the latter, namely I use this scheme: 我的问题是关于后者,即我使用以下方案:

  1. Send login request to server (in form of "login username password-encrypted") 将登录请求发送到服务器(以“登录用户名密码加密”的形式)

  2. (Client) Wait until server responds or until timeout of five seconds happens. (客户端)等待服务器响应或直到发生五秒钟的超时。

  3. (Server) Respond either with "loginconfirmed" or "logindenied". (服务器)以“ loginconfirmed”或“ logindenied”响应。

So I am wondering what is the best way to code this, I have some old code here, but I think the coupling in here is way too high and I have already rewritten part of the framework around this code (It also resides in a graphical class, which makes no sense at all and I shouldn't have done that): 所以我想知道什么是最好的编码方法,这里有一些旧代码,但是我认为这里的耦合太高了,我已经围绕该代码重写了框架的一部分(它也驻留在图形中类,这根本没有意义,我不应该这样做):

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

I use synchronisation, but I don't really like it, so if possible I would want to avoid it. 我使用同步,但是我不太喜欢它,所以如果可能的话,我会避免使用它。 However the problem kind of is that the network runs in a different thread, and a responsive can come in any moment, however there are only five seconds in which the login process wants a response. 但是,问题的类型是网络在不同的线程中运行,并且响应可以随时出现,但是登录过程只需要五秒钟即可响应。

Rewritten code without networking: 无需网络即可重写代码:

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

In the new code it should start with the networking after the gui.setPanel(new LoadingPanel()); 在新代码中,它应该从gui.setPanel(new LoadingPanel());之后的联网开始gui.setPanel(new LoadingPanel()); .

So once more to repeat the main question: How can I make the Networking class (a class reading responses from the server and processing them) only react to "loginconfirmed" and "logindenied" in a given timeout at a given moment, and redirect the event to the given LoginProcedure object? 因此,再次重复一个主要问题: 如何使Networking类(从服务器读取响应并对其进行处理的类)仅在给定的超时时间内在给定的时间对“ loginconfirmed”和“ logindenied”做出反应,并重定向给定LoginProcedure对象的事件?

I would design it in such a way as to enable a sync/async messaging system. 我将以启用同步/异步消息传递系统的方式进行设计。

  • Each exchangeable message must have a UUID, and a 'originID' property. 每个可交换消息必须具有UUID和'originID'属性。
  • An async message is simply sent from the emitter to the receiver. 异步消息只是从发射器发送到接收器。
  • A synchronous message have its content sent to the receiver, and enters a 'waiting reply' queue. 同步消息将其内容发送到接收者,并进入“等待答复”队列。 The caller thread is paused, or pings the queue from time to time. 调用者线程被暂停,或不时对队列执行ping操作。
  • The receiver parses the original message, prepares a reply and fills the originID property with the original message's ID. 接收者解析原始消息,准备回复,并用原始消息的ID填充originID属性。
  • The reply message is sent to the emitter. 回复消息发送到发射器。
  • The emitter parses it, recognizes that it's a reply, and signals the 'waiting reply' queue. 发射器对其进行解析,识别出它是一个答复,并向“等待答复”队列发出信号。
  • The original thread is allowed to proceed, with the reply in hand. 允许原始线程继续进行,并附带回复。
  • If no reply arrives, then a TimeOutException may be raised. 如果没有答复到达,则可能引发TimeOutException。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM