我正在为客户端到服务器应用程序创建一个登录服务器。
基本上有5台服务器,所有这些服务器都连接到一台登录服务器。
客户端可以连接到这5个服务器中的任何一个,但需要使用用户名和密码进行身份验证。身份验证应该在登录服务器中完成,登录服务器应该返回应该将答案返回给客户端的实际服务器的答案。
就像那样:
客户 - >服务器 - >登录服务器 - >服务器 - >客户(响应代码)
现在,我使用的是Netty,它是NIO,它不是每个客户端的线程。现在,要使用NIO进行身份验证,我们必须等待从登录服务器到达的响应,这可能需要一段时间并延迟其他想要登录的客户端,实际上您不能只是等待NIO的回答,就像那样。所以我想到了如何让它发挥作用的想法。我的想法是在另一个线程上运行请求并使用onResponse(String key, int responseCode)
方法生成一个事件,然后将客户端的通道放在带有生成密钥的映射中,这样我们就可以知道响应属于谁。因此,当我们进行身份验证时,我们会发送密钥和用户数据。
但我觉得这是一种糟糕的方式,并且有一种更有效的方法来做到这一点。有什么想法吗?
答案 0 :(得分:2)
假设您完全控制所有系统:
为服务器中的每个客户端连接分配ID。然后,当您需要对用户进行身份验证时,请在从服务器到登录服务器的请求中包含此连接ID,并在不等待登录服务器的回复的情况下返回。
将来某个时候您的服务器将从登录服务器接收登录响应。如果登录响应包含客户端连接ID - 使用该ID查找从服务器到客户端的连接,并将该回复转发回客户端。
答案 1 :(得分:1)
我是这样做的。
<强>设置强>
创建一个Channel包装器类,以便您可以识别哪个通道属于哪个客户端。
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 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));
上面的代码将找到匹配的客户端频道并将消息写入其中。
答案 2 :(得分:1)
您担心会阻止NIO工作线程,但您会转动另一个线程来执行登录。无论如何,你只使用了一个线程。因此,在服务器中为http(s)定义更多线程并完成它。除非你期望超过100个并发登录,否则这里没有问题。
NIO被高估了;操作系统非常适合调度线程和上下文切换,比使用asyn apis进行后空翻时更好。等待线程不消耗CPU。
答案 3 :(得分:0)
我知道你说你在Netty上。我只需要谈谈servlet api(如果你可以使用它):
仅供参考,这是使用servlet api 3.0+解决的问题,它允许您在AsynContext中执行完全相同的工作。不开玩笑,阅读servlet 3.0,最好是javaone youtube演示文稿和教程,甚至PDF规范都比javadoc更好。
如果您甚至想在servletinputstream / servletoutputstream上执行NIO,您可以使用servlet api 3.1执行此操作(尽管有点涉及)。 javaone演示文稿(2014年我认为)很棒。