几个基本功能描述
消息协议定义,消息编解码,连接认证,链路有效性校验机制,链路的断开重连机制。
主要设计
消息协议设计:消息头+消息体。消息头定义了基本协议字段定义,添加attachment方便扩展。Object编解码使用Marshaller。
链路交互设计:链路什么时候建立,什么时候关闭,握手请求与相应。
可靠性设计:心跳检查机制,重连机制,重复登录保护,消息缓存重发。
安全性设计:本章使用基于ip地址的白名单安全认证机制。
可扩展性设计:添加attachment方便扩展。
顺便给大家推荐一个Java技术交流群:473984645里面会分享一些资深架构师录制的视频资料:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多!
具体实现
编解码
编码
编码类继承MessageToByteEncoder,然后编码类重写了encode方法,把具体的消息存放到ByteBuf中就可以了。
解码
解码类继承LengthFieldBasedFrameDecoder:可以根据消息的长度进行拆包,自动的TCP粘包、半包处理。然后解码类重写decode方法进行解析即可。
如上编解码中使用Marshaller对Object对象编解码。
握手与安全认证
TCP建立连接之后,客户端发起握手,服务端进行验证,
客户端LoginAuthReqHandler
重写了channelActive方法,发送登录请求。
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(buildLoginReq());
}
private NettyMessage buildLoginReq() {
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setType(MessageType.LOGIN_REQ.value());
message.setHeader(header);
return message;
}
重写了channelRead方法
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
NettyMessage message = (NettyMessage) msg;
// 如果是握手应答消息,需要判断是否认证成功
if (message.getHeader() != null
&& message.getHeader().getType() == MessageType.LOGIN_RESP
.value()) {
byte loginResult = (byte) message.getBody();
if (loginResult != (byte) 0) {
// 握手失败,关闭连接
ctx.close();
} else {
System.out.println("Login is ok : " + message);
ctx.fireChannelRead(msg);
}
} else
ctx.fireChannelRead(msg);
}
服务端LoginAuthRespHandler
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
NettyMessage message = (NettyMessage) msg;
// 如果是握手请求消息,处理,其它消息透传
if (message.getHeader() != null
&& message.getHeader().getType() == MessageType.LOGIN_REQ
.value()) {
String nodeIndex = ctx.channel().remoteAddress().toString();
NettyMessage loginResp = null;
// 重复登陆,拒绝
if (nodeCheck.containsKey(nodeIndex))