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

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

问题描述:

我正在为我的客户端到服务器应用程序创建登录服务器。服务器到客户端的服务器身份验证 - 单线程

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

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

因此,它像:

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

现在,我使用的Netty和它的NIO,它不是thread-每个客户端。现在,为了与NIO进行身份验证,我们必须等待来自登录服务器的响应,这可能需要一段时间并延迟其他希望登录的客户端,实际上,您不能等待NIO的解答。所以我想到了一个想法,我该如何让它工作。我的想法是在不同的线程上运行请求,并使用onResponse(String key, int responseCode)方法处理事件,然后将客户端的频道放入带有生成密钥的地图中,这样我们就可以知道响应属于哪个人。所以当我们进行身份验证时,我们会发送密钥和用户数据。

但我觉得这是一个坏的方法,有一个更有效的方法来做到这一点。有任何想法吗?

+0

AFAIK netty支持使用每个连接的线程来阻塞NIO。请注意,NIO的* default *行为是阻塞操作,直到最近只有Socket支持非阻塞操作作为选项。 –

+0

在多服务器环境中,使用地图保留通道时会被破坏。 – eg04lt3r

+0

只是一个建议,因为你要求更好的方法来做到这一点 - 如果你使用Java,你可能需要查看websockets,例如html 5 + http(s)。然后,您为每个客户端模型获得一个线程,使用加密进行身份验证对您的应用程序是透明的,并且您可以获得NIO的所有功能,而无需部署最终客户端。 – MuffinMan

假设你有所有系统的完全控制:

分配一个ID为服务器中的每个客户端连接。然后,当您需要验证用户时,请将此连接ID包含在从服务器到登录服务器的请求中,然后返回而无需等待登录服务器的答复。

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

这是我做到的。

设置

创建频道包装类,这样就可以识别哪个通道属于哪个客户端。

public class CustomChannel implements Channel { 

    private final Channel channel; 
    private final String clientId; 

    ... 
} 

创建匹配的客户端的通道自定义ChannelMatcher:

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 = 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中使用asyn apis做后空翻更好。等待线程不消耗CPU。

我知道你说你是在Netty上。我只需要说一些关于servlet api的东西(如果你可以使用它):

仅供参考,这是servlet api 3.0+的问题,它允许您在AsynContext中执行完全相同的工作。不要开玩笑,仔细阅读servlet 3.0,最好是javaone youtube演示文稿和教程,即使PDF规范比javadoc更好。

如果你甚至想在servletinputstream/servletoutputstream上执行NIO,你可以使用servlet api 3.1来实现(尽管有点牵扯)。 javaone演示文稿(2014我认为)非常棒。