1:前言
最近在学习网络知识,对于java开发来说,Netty是一个非常重要的框架,无论是为了面试还是日常工作中,如RPC框架Dubbo底层其实是用了Netty, 又或者我们的聊天通信功能,都可能有Netty的身影,作为java开发者 我们应该掌握它。此项目是一个前后端分离的、以Netty为核心,以Websocket为通信协议的聊天系统,整体功能仿照电脑版微信, 但是电脑版微信功能非常多,因此只实现部分功能,如:用户登录(oauth2认证)、查看我的好友列表、单聊、创建群聊、群消息发送、删除聊天、置顶聊天、表情功能发送、文件发送、心跳和空闲检测。git项目地址:https://github.com/holiday-jq/springboot-netty.git
2:技术路线
- 前端: Webpack + vue + less + element ui
- 后端:springboot框架 + Netty网络编程框架 + spring-security-oauth2 + jdbcTemplate
- 数据库: mysql
- 协议: websocket
2.1什么是Spring Boot?
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是 Spring Boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 Maven 整合了所有的 Jar 包,Spring Boot 整合了所有的框架。
2.2什么是Netty?
Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。
Netty 是一个广泛使用的 Java 网络编程框架(Netty 在 2011 年获得了Duke’s Choice Award,见https://www.java.net/dukeschoice/2011)。它活跃和成长于用户社区,像大型公司 Facebook 和 Instagram 以及流行 开源项目如 Infinispan, HornetQ, Vert.x, Apache Cassandra 和 Elasticsearch 等,都利用其强大的对于网络抽象的核心代码。
2.3关于WebSocket通信协议
简单说一下WebSocket通信协议,WebSocket是为了解决HTTP协议中通信只能由客户端发起这个弊端而出现的,WebSocket基于HTTP5协议,借用HTTP进行握手、升级,能够做到轻量的、高效的、双向的在客户端和服务端之间传输文本数据。
3:环境搭建
- 前端: 运行环境搭建:首先要安装Node.js 安装链接https://nodejs.org/zh-cn/
然后运行cmd进入控制台 验证是否安装成功: node -v 和 npm -v 如果能显示版本号出来说明Node.js安装成功 用VsCode(或看个人喜欢用什么编辑器),到项目根目录,首先执行npm install安装依赖,然后npm run serve启动一个node服务就可以访问前端资源 - 后端: 安装配置好maven,并在开发编辑器(如eclipse、intellij idea)中配置好maven,然后启动springboot工程
4:具体功能展示
-
用户登录:
这里采用oauth2的授权模式是password模式,用户验证成功后返回token,然后如果访问接口需要带token访问,因为设置了对接口资源进行保护,不然提示401错误
-
查看我的好友列表:
-
单聊
-
创建群聊和群消息发送:
此处做了判断,如果选择人数大于1就创建的是群聊,如果选择人数是1的话,那就是创建单聊。
备注:这里的群聊图片不知道怎么实现将群成员的头像组合一张图片作为群聊的头像,就像微信创建群聊那样,所以随便找了张图片作为群聊的头像,所以无论创建多少个群,群聊头像都是一样的。 -
右键鼠标弹出删除聊天和置顶聊天:
备注: 此处置顶和取消置顶交互效果写得不好,如果再新增聊天,原来置顶的那条聊天就不能一直在最前面,待优化。!! -
表情功能发送:
-
文件发送和下载:
-
心跳和空闲检测:
Netty的IdleStateHandler心跳机制主要是用来检测远端是否存活,如果不存活或活跃则对空闲Socket连接进行处理避免资源的浪费;前端会有一个定时器,每隔30秒就会发一个心跳包到Netty,发送心跳包是为了避免触发检测机制,如果触发了检测机制,就会执行channelIdle方法,你可以在这里关闭channel连接。 -
题外话:空闲检测这个ChannelHandler最好放在Netty ChannelPipeline的最前面。
-
为什么空闲检测要插入到最前面?因为如果插入到最后面的话,如果这条连接读到了数据,但是在传播的过程中出错了或者数据处理完后不往后面传递,最终IMIdleStateHandler就不会读到数据 、导致误判
-
如果没有空闲检测的话,可能会出现连接假死的情况,会带来以下问题:
1:对于服务端来说,因为每条连接都会耗费cpu和内存资源,(当服务端accpt成功会返回一个文件描述符,linux一切皆文件),大量假死的连接会逐渐耗光服务器的资源,最终导致性能逐渐下降。
2:对于客户端来说:连接假死会造成发送数据超时,影响用户体验。
5:总结与扩展
因为聊天软件的功能非常多,所以不可能全部功能都实现(太难了- _ -),其实还有很多优化和没实现的功能,例如群聊那里,可以增加退群功能,和拉人进群功能,在服务端无非是对ChannelGroup进行添加和删除,前端交互效果稍微繁琐点,还有聊天文字输入框可以用富文本编辑器实现,此项目是用了textarea标签(新浪博客网页版聊天也是用的textarea哈哈),然后聊天记录和列表怎么做持久化,滚动加载以前的聊天记录,此项目没做(能力有限- _ -),所以刷新界面后就看不到之前的聊天记录。