5 定义一个Handler实现身份校验
在客户端与服务器端之间通信时,一定要进行身份认证,即客户端必须要登录。此时可以在用户登录完成后,在channel上添加一个标志位,表示用户已经登录。在接受客户端发送的消息时,必须确保此时客户端已经登录。
在客户端登录后,在channel上添加一个标志位。
在服务器端的LoginRequestHandler中,用户登录成功后,就将channel添加一个“login”的标志位,并设置为true。
ctx.channel().attr(AttributeKey.newInstance("login")).set(true);
添加一个身份认证Handler,放在LoginRequestHandler的后面,表示后面的所有请求都必须要经过身份认证,没有经过身份认证的话就关闭连接。
public class AuthHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//如果没有登录,则关闭连接
Boolean login =(Boolean) ctx.channel().attr(AttributeKey.newInstance("login")).get();
if(login == null || !login){
ctx.channel().close();
}
// 否则的话就直接传给下一个handler处理
else {
super.channelRead(ctx, msg);
}
}
}
以上解决方案存在的问题:这样客户端每次发送数据给服务器端时,都需要去校验,性能会受到影响。
我们可以在第一次校验之后,只要连接未断开都不再做校验!
可以通过pipeline的热插拔机制实现。
只需要在上面的代码中加入移除handler的代码即可,即校验通过后,就将AuthHandler删除。
public class AuthHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//如果没有登录,则关闭连接
Boolean login =(Boolean) ctx.channel().attr(AttributeKey.newInstance("login")).get();
if(login == null || !login){
ctx.channel().close();
}
// 否则的话就直接传给下一个handler处理,并删除AuthHandler
else {
ctx.pipeline().remove(this); //移除该handler即可。
super.channelRead(ctx, msg);
}
}
}
6 实现一对一私聊功能
我们之前都是客户端跟服务器端通信,要实现客户端与客户端之间的通信,肯定是要通过服务器端进行转发的,那么我们需要告诉服务器端,我要发送消息给谁并且附带上消息内容。
这时候要解决的问题就是,服务器端收到数据包后解析,直到了要发给那个用户,但是怎么通过用户的ID找到与用户连接的channel?
这时可以将用户连接并且登录后的channel保存起来,利用Map或者其他方式将其一一对应起来,当需要发送消息给张三的时候,就去Map中找张三与服务器端建立连接的channel,通过channel将消息转发给张三。