Java 客户端的服务器到服务器身份验证-单线程

Java 客户端的服务器到服务器身份验证-单线程,java,multithreading,networking,netty,Java,Multithreading,Networking,Netty,我正在为客户端到服务器应用程序创建登录服务器 基本上有5台服务器,所有这些服务器都连接到一个登录服务器 客户端可以连接到这5台服务器中的任何一台,但它需要使用用户名和密码进行身份验证。身份验证应该在登录服务器中完成,并且登录服务器应该向实际服务器返回一个答案,而实际服务器应该向客户端返回答案 所以它是这样的: 客户端->服务器->登录服务器->服务器->客户端(响应代码) 现在,我使用的是Netty,它是NIO,不是每个客户端的线程数。现在,为了使用NIO进行身份验证,我们必须等待来自登录服务器

我正在为客户端到服务器应用程序创建登录服务器

基本上有5台服务器,所有这些服务器都连接到一个登录服务器

客户端可以连接到这5台服务器中的任何一台,但它需要使用用户名和密码进行身份验证。身份验证应该在登录服务器中完成,并且登录服务器应该向实际服务器返回一个答案,而实际服务器应该向客户端返回答案

所以它是这样的:

客户端->服务器->登录服务器->服务器->客户端(响应代码)

现在,我使用的是Netty,它是NIO,不是每个客户端的线程数。现在,为了使用NIO进行身份验证,我们必须等待来自登录服务器的响应,这可能需要一段时间并延迟其他想要登录的客户机,实际上,您不能像那样等待NIO的响应。所以我想到了一个如何让它工作的主意。我的想法是在不同的线程上运行请求,并使用
onResponse(String-key,int-responseCode)
方法创建一个事件,然后使用生成的密钥将客户端的通道放入映射中,这样我们就可以知道响应属于谁。因此,当我们进行身份验证时,我们会发送密钥和用户数据


但我觉得这是一种不好的方法,有一种更有效的方法可以做到这一点。有什么想法吗?

假设您完全控制了所有系统:

为服务器中的每个客户端连接分配一个ID。然后,当您需要对用户进行身份验证时,将此连接ID包含在从服务器到登录服务器的请求中,并在不等待登录服务器答复的情况下返回

在将来的某个时候,您的服务器将收到来自登录服务器的登录响应。如果登录响应包含客户机连接ID-使用该ID查找从服务器到客户机的连接,并将该响应转发回客户机。

以下是我的操作方法

设置

创建一个通道包装类,以便您可以识别哪个通道属于哪个客户机

public class CustomChannel implements Channel {

    private final Channel channel;
    private final String clientId;

    ...
}
创建自定义通道匹配器以匹配客户端的通道:

public class CustomChannelMatcher implements ChannelMatcher {
    private final String clientId;

    public CustomChannelMatcher(String clientId) {
        this.clientId = clientId;
    }

    @Override
    public boolean matches(Channel channel) {
        if (channel instanceof CustomChannel) {
            return clientId.equals(((CustomChannel) channel).getClientId());
        }
        return false;
    }

    ...
}
处理请求

在客户端处理程序中,使用ChannelGroup跟踪客户端的频道

ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

...

channelGroup.add(new CustomChannel(ctx.channel(), clientId));

// send request to another server without blocking
处理响应

在服务器处理程序中,使用CustomChannelMatcher匹配客户端的通道

// when the server responds sometimes later

channelGroup.writeAndFlush(responseMessage, 
    new CustomChannelMatcher(clientId));

上面的代码将找到一个匹配的客户端通道,并将消息写入其中。

您担心会阻止一个NIO工作线程,但您会旋转另一个线程来执行登录。反正你又用了一根线。因此,在您的服务器中为http定义更多线程,并完成它。除非您预期会有100多个并发登录,否则这里没有问题


NIO被高估了;该操作系统在调度线程和上下文切换方面非常出色,比在java中使用ASYNAPI进行backflip要好得多。等待线程不会消耗CPU。

我知道你说过你在上网。不过,我只需要谈谈servlet api(以防您可以使用它):

仅供参考,这是ServletAPI3.0+解决的问题,它允许您在AsyncContext中准确地执行该工作。不是开玩笑,请阅读Servlet3.0,最好是javaone youtube演示和教程,甚至PDF规范也比javadoc好


如果您甚至想在servletinputstream/servletoutputstream上执行NIO,您可以使用ServletAPI3.1来执行(尽管有点复杂)。javaone演示(我认为是2014)很棒。

AFAIK netty支持使用每个连接一个线程来阻止NIO。注意NIO的默认行为是阻塞操作,直到最近,只有套接字支持非阻塞操作作为选项。在多服务器环境中,使用map保留通道时,它将被破坏。只是一个建议,因为您要求更好的方法来实现这一点——如果您使用的是Java,您可能需要研究WebSocket,即HTML5+http。然后,您可以使用每个客户端的线程模型,使用加密的身份验证对您的应用程序是透明的,并且您可以获得NIO的所有功能,而无需部署终端客户端。