专栏首页Java技术栈Netty 通道怎么区分对应的用户?很多人搞错了!

Netty 通道怎么区分对应的用户?很多人搞错了!

前言

考虑一个功能业务,在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模块可以安全的识别某个通道属于某个用户?(这个可以像上面一样的方式解决)
  • nettysocket模块接收到一条消息又任何证明这条通道是可信的?

nett的实现中是没有认证也没有HttpSession这个东西的,也就是说.在netty程序线程中是无法得到web项目登录的用户情况的。另外,Netty 系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。

出于这点,参考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不保证全局唯一!!

另外,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的 Java 系列面试题和答案,非常齐全。

本文分享自微信公众号 - Java技术栈(javastack),作者:点击关注 ????

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 漫谈Java IO之基础篇

    Java的网络编程如果不是专门搞服务器性能开发或者消息分发,几乎可能涉及不到。但是它却是面试找工作必问的一个知识点,涵盖的知识体系也非常广泛,从Java底层I...

    用户1154259
  • 史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战

    原作者江成军,原题“还在被Java NIO虐?该试试Netty了”,收录时有修订和改动。

    JackJiang
  • 当Tomcat遇上Netty

    分部给到的异常日志大概是这样(鉴于公司规定禁止截图禁止拍照禁止外传任何信息,下面是我网上找到一张类似的报错):

    彤哥
  • 五分钟学Java:如何学习Java面试必考的网络编程

    Java作为一门后端语言,对于网络编程的支持是必不可少的,但是,作为一个经常CRUD的Java工程师,很多时候都不需要接触到网络编程,自然而然地对这个东西不那么...

    黄小斜学Java
  • 五分钟学Java:如何学习Java面试必考的网络编程

    Java作为一门后端语言,对于网络编程的支持是必不可少的,但是,作为一个经常CRUD的Java工程师,很多时候都不需要接触到网络编程,自然而然地对这个东西不那么...

    Java技术江湖
  • 5年经验Java程序员面试20天,拿下数个offer,总结出的经验感想!

    今天分享的是一位5年工作经验的Java工程师在帝都的面试经验总结,看看这些互联网公司都爱问些什么题,希望对大家的面试有指导意义。 从事Java开发也有5年经验了...

    Java知音
  • 项目经验不丰富、技术不突出的程序员怎么打动面试官?前言 关于项目经验关于基本技术关于个人潜力结语

    相信不少的程序员都有过类似的困惑:如果我没有大型的项目经历,也不能靠技术征服面试官,那我要怎么才能给面试官留下一个好印象呢?

    美的让人心动
  • 淘宝面试回来,想对程序员们谈谈

    因为我是一个不管做什么事情都喜欢进行总结的一个人。所以对于在上周去淘宝面试的经历,现在面试回来总结,我想对所有程序员们谈谈。

    AI乔治
  • 2021 最新的Java 后端学习路线!凎!

    断断续续写了大半个月,终于把 2021 最新版的 Java 后端学习路线给整完了!

    Guide哥
  • 普通程序员如何让面试官无以言表并高薪聘请?

    相信不少的程序员都有过类似的困惑:如果我没有大型的项目经历,也不能靠技术征服面试官,那我要怎么才能给面试官留下一个好印象呢?

    Java知音
  • 超详细Netty入门,看这篇就够了!

    本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路。

    java技术爱好者
  • 淘宝面试回来,想对程序员们谈谈

    因为我是一个不管做什么事情都喜欢进行总结的一个人。所以对于在上周去淘宝面试的经历,现在面试回来总结,我想对所有程序员们谈谈。

    烂猪皮
  • 项目经验不丰富、技术不突出的程序员怎么打动面试官?

    项目的整体架构,在面试的时候能够清楚地画给面试官看并且清楚地指出从哪里调用到哪里、使用什么方式调用

    JAVA高级架构开发
  • 从 BIO、NIO 聊到 Netty,还要手写一个 RPC 框架!毕设/项目经验稳了!

    早期的 Java 网络相关的 API(java.net包) 使用 Socket(套接字)进行网络通信,不过只支持阻塞函数使用。

    Guide哥
  • 金三银四季,阿里工作10多年Java大牛的“心得”,献给迷茫中的你

    当你从事Java一年后,重新找工作时,才会真实的感受到“金三银四”这四个字背后的意思。

    秃顶的Java程序员
  • JAVA服务器推送功能设计,消息方法总结

    IT架构圈
  • Netty 长连接服务

    来源:Dozer's Technology Blog 链接:https://www.dozer.cc/2014/12/netty-long-connectio...

    java达人
  • 三七互娱秋招提前批 java服务端

        我是在6月5号参加了三七互娱的秋招的web后端线上笔试,第二天又参加了java服务端的线上笔试,之后去三七大楼参加open day,然后面试时一面,二面...

    牛客网
  • 宝贝儿!你要的Netty常见面试题总结,Guide搞来了!

    Netty 总算总结完了,Guide 也是长舒了一口气。有太多读者私信我让我总结 Netty 了,因为经常会在面试中碰到 Netty 相关的问题。

    Guide哥

扫码关注云+社区

领取腾讯云代金券