Netty 通道怎么区分对应的用户?

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Redis 版,经济版 1GB 1个月
简介: 前言考虑一个功能业务,在web程序中向指定的某个用户进行实时通讯

前言

考虑一个功能业务,在web程序中向指定的某个用户进行实时通讯


在Web运用的Socket通讯功能中(如在线客服),为保证点对点通讯.而这个看似简单的根据用户寻到起channel通道实际会碰到不少问题


web程序中的Http协议是无状态的

一般项目中socket服务和web项目是独立部署的

socket连接存在重连的情况,而Channel对象每次都不一样

Channel是面向网卡绑定的,无法序列化

解决方案

通过管理一个线程安全的用户标识(如用户主键)和对应channel的map链表


private final ConcurrentHashMap channelMap = new ConcurrentHashMap<>();

那么问题来了,


在netty模块中怎么得到这个用户标识?

又如何保证netty socket模块可以安全的识别某个通道属于某个用户?(这个可以像上面一样的方式解决)

netty socket模块接收到一条消息又任何证明这条通道是可信的?

在netty的实现中是没有认证也没有HttpSession这个东西的,也就是说.在netty程序线程中是无法得到web项目登录的用户情况的.


出于这点,参考web项目集群的session共享方案.可以在Redis等缓存中保存登录信息.

image.png

在web项目中登录之后在redis中在这个以用户id为名的key中保存一个token,

在客户端socket通道建立之后立马发送包含一个用户标识和ASK到socket服务端,

服务端根据ASK计算一个token和redis比对.一旦比对成功,则绑定当前channel和用户之间的关系;

之后server每接收到一条消息就检测当前通道有没有绑定用户信息

这个key是一次性的.这点非常重要,试想一下.在你前台项目可能因为cookie过期或者后台已经自动将该用户下线,而你的用户标识和ASK暴露.那么就可能被恶意连接发送消息;


另外关于token和ASK之类的验证传输如果仅仅是为了识别和绑定用户与channel的关系,这点也是可以忽略的,只要redis中保存该用户的登录状态即可,通道建立的第一次通讯就传输当前浏览器的登录用户标识,再去redis中比对即可,但是redis中的这个key还是一次性的好,避免一个用户建立多条socket通道


正确的绑定通道Channel和用户之间的关系

如果我们仅仅有一个ConcurrentHashMap,是无法快速优雅的判断当前channel是属于哪个用户的;我看到别人绝大多数的实现是在创建一个channelId和用户标识的Map来管理


//key为channel的长id,channel.id().asLongText();value为用户id

private final ConcurrentHashMap channelAndUserMap = new ConcurrentHashMap<>();

1

其实这不是最合理的做法,正确的做法是利用Channel对象提供的AttributeMap来保存该通道的附带信息,很多人不知道Channel对象提供了一个绑定自定义数据的Map


使用示例:

//用户id=>channel示例
private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
/**
 * 判断一个通道是否有用户在使用
 * 可做信息转发时判断该通道是否合法
 * @param channel
 * @return
 */
public boolean hasUser(Channel channel) {
    AttributeKey<String> key = AttributeKey.valueOf("user");
    return (channel.hasAttr(key) || channel.attr(key).get() != null);//netty移除了这个map的remove方法,这里的判断谨慎一点
}
/**
 * 上线一个用户
 *
 * @param channel
 * @param userId
 */
public void online(Channel channel, String userId) {
    //先判断用户是否在web系统中登录?
    //这部分代码个人实现,参考上面redis中的验证
        this.channelMap.put(userId, channel);
        AttributeKey<String> key = AttributeKey.valueOf("user");
        channel.attr(key).set(userId);
}
/**
 * 根据用户id获取该用户的通道
 *
 * @param userId
 * @return
 */
public Channel getChannelByUserId(String userId) {
    return this.channelMap.get(userId);
}
/**
 * 判断一个用户是否在线
 *
 * @param userId
 * @return
 */
public Boolean online(String userId) {
    return this.channelMap.containsKey(userId) && this.channelMap.get(userId) != null;
}

注意!!

很多人拿channel.id().asShortText()来记录标识channel,这是错误的!!!!!短id不保证全局唯一!!

image.png

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
安全 Java 容器
Netty通道的容器属性Attribute
Netty中的Channel通道类,有类似于Map的容器功能,可以通过“key-value”键值对的形式来保存任何Java Object的值。一般来说可以存放一些与通道实例相关联的属性,比如说服务期端的ServerSession会话实例。
|
12月前
|
网络协议 前端开发 Java
Netty异步NIO框架(一)java服务端与客户端实现聊天 websocket通道
Netty异步NIO框架(一)java服务端与客户端实现聊天 websocket通道
|
设计模式 缓存 网络协议
Netty4 Channel 概述(通道篇)
Netty4 Channel 概述(通道篇)
Netty4 Channel 概述(通道篇)
【Netty】NIO 通道 ( Channel ) 组件(三)
【Netty】NIO 通道 ( Channel ) 组件(三)
121 0
【Netty】NIO 通道 ( Channel ) 组件(三)
【Netty】NIO 通道 ( Channel ) 组件(二)
【Netty】NIO 通道 ( Channel ) 组件(二)
175 0
【Netty】NIO 通道 ( Channel ) 组件(二)
|
网络协议 Java
【Netty】NIO 通道 ( Channel ) 组件(一)
【Netty】NIO 通道 ( Channel ) 组件(一)
115 0
【Netty】NIO 通道 ( Channel ) 组件(一)
|
Java API
【Netty】NIO 简介 ( NIO 模型 | NIO 三大组件 | 选择器 Selector | 通道 Channel | 缓冲区 Buffer | NIO 组件分配 | 缓冲区示例 )
【Netty】NIO 简介 ( NIO 模型 | NIO 三大组件 | 选择器 Selector | 通道 Channel | 缓冲区 Buffer | NIO 组件分配 | 缓冲区示例 )
147 0
【Netty】NIO 简介 ( NIO 模型 | NIO 三大组件 | 选择器 Selector | 通道 Channel | 缓冲区 Buffer | NIO 组件分配 | 缓冲区示例 )
|
API
【Netty】NIO 选择器 ( Selector ) 通道 ( Channel ) 缓冲区 ( Buffer ) 网络通信案例
【Netty】NIO 选择器 ( Selector ) 通道 ( Channel ) 缓冲区 ( Buffer ) 网络通信案例
177 0
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13285 1
|
9天前
|
机器学习/深度学习 缓存 算法
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk