服务器到客户端的服务器身份验证 - 单线程
我正在为我的客户端到服务器应用程序创建登录服务器。服务器到客户端的服务器身份验证 - 单线程
基本上有5个服务器,并且所有这些服务器都连接到一个登录服务器。
客户端可以连接到这5台服务器中的任何一台,但需要使用用户名和密码进行认证。身份验证应该在登录服务器中完成,并且登录服务器应该向实际的服务器返回应答,以便将答案返回给客户端。
因此,它像:
客户端 - >服务器 - >登录服务器 - >服务器 - >客户端(响应代码)
现在,我使用的Netty和它的NIO,它不是thread-每个客户端。现在,为了与NIO进行身份验证,我们必须等待来自登录服务器的响应,这可能需要一段时间并延迟其他希望登录的客户端,实际上,您不能等待NIO的解答。所以我想到了一个想法,我该如何让它工作。我的想法是在不同的线程上运行请求,并使用onResponse(String key, int responseCode)
方法处理事件,然后将客户端的频道放入带有生成密钥的地图中,这样我们就可以知道响应属于哪个人。所以当我们进行身份验证时,我们会发送密钥和用户数据。
但我觉得这是一个坏的方法,有一个更有效的方法来做到这一点。有任何想法吗?
假设你有所有系统的完全控制:
分配一个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我认为)非常棒。
AFAIK netty支持使用每个连接的线程来阻塞NIO。请注意,NIO的* default *行为是阻塞操作,直到最近只有Socket支持非阻塞操作作为选项。 –
在多服务器环境中,使用地图保留通道时会被破坏。 – eg04lt3r
只是一个建议,因为你要求更好的方法来做到这一点 - 如果你使用Java,你可能需要查看websockets,例如html 5 + http(s)。然后,您为每个客户端模型获得一个线程,使用加密进行身份验证对您的应用程序是透明的,并且您可以获得NIO的所有功能,而无需部署最终客户端。 – MuffinMan