前言

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

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

  1. web程序中的Http协议是无状态的
  2. 一般项目中socket服务和web项目是独立部署的
  3. socket连接存在重连的情况,而Channel对象每次都不一样
  4. Channel是面向网卡绑定的,无法序列化

解决方案

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

    private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();

那么问题来了,

  • netty模块中怎么得到这个用户标识?
  • 又如何保证netty socket模块可以安全的识别某个通道属于某个用户?(这个可以像上面一样的方式解决)
  • netty socket模块接收到一条消息又任何证明这条通道是可信的?

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

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

  1. web项目中登录之后在redis中在这个以用户id为名的key中保存一个token,
  2. 在客户端socket通道建立之后立马发送包含一个用户标识ASKsocket服务端,
  3. 服务端根据ASK计算一个tokenredis比对.一旦比对成功,则绑定当前channel和用户之间的关系;
  4. 之后server每接收到一条消息就检测当前通道有没有绑定用户信息

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

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

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

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

    //key为channel的长id,channel.id().asLongText();value为用户id
private final ConcurrentHashMap<String, String> channelAndUserMap = new ConcurrentHashMap<>();

其实这不是最合理的做法,正确的做法是利用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不保证全局唯一!!

项目系统Netty的Channel和用户之间的关系绑定正确做法,以及Channel通道的安全性方案的更多相关文章

  1. 如何理解springcloud微服务项目中,eureka,provider,consumer它们之间的关系?

    eureka负责注册provider和consumer的服务信息 provider负责与数据库进行交互,实现数据持久化,并给consumer提供服务 consumer与前端交互,通过与Eureka同源 ...

  2. 关于计算机的ID和用户ID之间的关系

    关于计算机的ID和用户ID之间的关系 计算机安装完系统后就会生成计算机ID,然后系统会以计算机ID为前缀附加数字创建Administrator(500)和Guest(501)用户ID,其他用户的ID将 ...

  3. GJM :用JIRA管理你的项目(三)基于LDAP用户管理 [转载]

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  4. PostgreSQL表空间、数据库、模式、表、用户/角色之间的关系

    看PostgreSQL9的官方文档,我越看越迷糊,这表空间,数据库,模式,表,用户,角色之间的关系怎么在PostgreSQL里这么混乱呢?经过中午的一个小实验,我逐渐理清了个中来龙去脉.下面我来还原我 ...

  5. PostgreSQL表空间、模式、表、用户/角色之间的关系

    PostgreSQL表空间.模式.表.用户/角色之间的关系是本文我们主要要介绍的内容,表空间,数据库,模式,表,用户,角色之间的关系到底是怎样的呢?接下来我们就开始介绍这一过程. 实验出角色与用户的关 ...

  6. 使用Jquery+EasyUI 进行框架项目开发案例讲解之二---用户管理源码分享

    使用Jquery+EasyUI 进行框架项目开发案例讲解之二 用户管理源码分享   在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享>我们分享 ...

  7. 使用Jquery+EasyUI 进行框架项目开发案例解说之二---用户管理源代码分享

    使用Jquery+EasyUI 进行框架项目开发案例解说之二 用户管理源代码分享  在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例解说之中的一个---员工管理源代码分享> ...

  8. “MVC+Nhibernate+Jquery-EasyUI” 信息发布系统 第四篇(用户管理功能的实现)

    “MVC+Nhibernate+Jquery-EasyUI” 信息发布系统 第四篇(用户管理功能的实现) 一.前三篇的内容是否对您有帮助呢?如果有的话,请您继续关注这篇吧,这篇主要是实现”用户管理“的 ...

  9. Linux 普通用户之间免密登陆

    目的: 同台机器之间实现普通用户之间的免密登陆: NN01 的user1 免密登陆 user2 不同机器之间实现普通用户之间的免密登陆 :NN01 的user1 免密登陆 NN01 的user1 一. ...

随机推荐

  1. 多元线性回归检验t检验(P值),F检验,R方等参数的含义

    做线性回归的时候,检验回归方程和各变量对因变量的解释参数很容易搞混乱,下面对这些参数进行一下说明: 1.t检验:t检验是对单个变量系数的显著性检验   一般看p值:    如果p值小于0.05表示该自 ...

  2. Bootstrap告警框(alert)实现弹出效果和短暂消失后上浮消失

    最近用到bootstrap的告警框时发现只有html的说明,就自己写了一个弹出告警框和弹出短暂显示后上浮消失的告警框. 直接上JS代码了,可以copy过去直接用(使用bootstrap的UI框架的情况 ...

  3. myblogplus 第二期 慕舲原创 如何删除官方在你博客内设置的所有广告

    问题描述: 文章下方广告渐多了起来,这也无可厚非,原来只有小小一幅的,毕竟博客园团队很卖力,博客园首页不是在更新吗,博问也在推广(虽然解答者不多,提问者很多) 不过无疑很影响美观,那些可以让他设置,不 ...

  4. Ant Design Vue使用支持v-model效验的FormModel表单遇到的一个坑

    按照官网上用法写好表单后,在a-select上绑定了change事件 <a-form-model-item label="类型" prop="config.type ...

  5. 快速解决Ubuntu/linux 环境下QT生成没有可执行文件(application/x-executable)

    快速解决Ubuntu/linux 环境下QT生成没有可执行文件(application/x-executable)(转载)   问题描述 与windows环境下不同,linux选择debug构建时并不 ...

  6. google protocol buffer——protobuf的编码原理二

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...

  7. 总结删除文件或文件夹的7种方法-JAVA IO基础总结第4篇

    本文是Java IO总结系列篇的第4篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  8. 聊一聊RocketMQ的注册中心NameServer

    前言 上次我们一起了解了RocketMQ的基本架构原理,那简单的回顾一下RocketMQ的架构组成. RocketMQ其实包含了四个核心部分,NameServer.Broker.Producer.Co ...

  9. Google Analytics谷歌分析事件之非互动事件

    非互动事件官方的解释如下 “非互动”一词是指可选的布尔值参数,此参数可以传递到用于发送事件命中的方法.通过此参数,您可以确定要如何为网站上包含事件衡量的网页定义跳出率.例如,假设您的首页上内嵌有一个视 ...

  10. c# 可获取系统环境

    c# 可获取系统环境, 启动进程执等 *.shell [MenuItem("Tools/DesignHelper/Clean and Pull")]     private sta ...