23-⾼并发-实例⼀、⾃定义ProBuf解码器:处理半包问题,将Bytebuf数据包->POJO
* 1.读取长度,如果长度位数不够,则终⽌读取。
* 2.然后读取魔数,版本号等其他字段。
* 3.最后按照净长度读取内容。如果内容字节数不够,则恢复到之前的起始位置,然后终⽌读取。⼆、⾃定义ProBuf编码器:处理半包问题,将POJO->Bytebuf数据包
* 1.写⼊字节码长度
* 2.写⼊其他字段,魔输,版本号等
* 3.写⼊POJO字节码内容
三、Protobuf消息格式设计
1.请求消息
2.应答消息
3.命令消息
四、登录流程
· 客户端编码:编码登录请求的Protobuf数据包编码。
· 服务器端解码:解码登录请求的Protobuf数据包解码。
· 服务器端编码:编码登录响应的Protobuf数据包编码。
· 客户端解码:解码登录响应的Protobuf数据包解码。
五、客户端
· ClientCommand模块:控制台命令收集器。
CommandContorller
initCommandMap()
初始化菜单
startCommandThread()
(1)connectFlag判断是否在连接,如果不在连接,启动连接线程,休眠命令线程。
(2)创建连接:设置连接connectListener
-----------------------------------
(1)获取通道线程,失败后10s重试连接
(2)成功后创建客户端会话session,绑定通道。
(3)成功后设置Connected。
(4)设置连接关闭closeListener
--------------------------------
(1)获取通道channel
(2)根据SESSION_KEY获取通道中的session
(3)关闭通道session.channel.close
·
设置Connected=false
·关闭channel
--------------------------------
--------------------------------
(5)唤醒命令线程。
-----------------------------------
(3)根据输⼊指令处理业务(登录/登出/聊天)。
(4)发送POJO:根据业务场景将消息组装成Protobuf数据包。通过客户端发往服务器。
ClientSession
⼀、胶⽔类
(1)通过user,可以获得当前的⽤户信息。
(2)通过channel,可以向服务器端发送消息。
·关闭通道:close()
·绑定通道:设置channel
·写数据帧:witeAndFlush(pkg) writeAndClose(pkg)
⼆、会话状态
(3)是否成功连接isConnected。
(4)是否成功登录isLogin。
三、绑定在通道上,将Session放⼊Channel。
· channel.attr=key:sessionKey value:this
· 设置初始sessionId=-1
·
四、会话变量存储
map
五、登录成功
服务端登录成功,客户端处理如下:
(1)获取session,设置SessionId
(2)设置isLogin
· ProtobufBuilder模块:Protobuf数据包构造者。
· Sender模块:数据包发送器。
LoginSender
User + Session
1.⽣成Protobuf登录数据包。
2.调⽤BaseSender发送。(从session中获取channel)ChatSender
ChatMsg[user+time+from(userID)+FromNick]+[to(touid)+msgID+content+type]
· Handler模块:服务器响应处理器。
处理器
⼀、LoginResponceHandler处理器
(1)如果服务端登录成功,接到响应后保存session,设置登录成功状态。
(2)如果消息不是请求响应,传递到下⼀流⽔线。
(3)登录成功后,移除处理器,因为不需要在处理登录了。
同时,开启⼼跳处理器。
⼆、ChatMsgHandler处理器
(1)对消息类型类型进⾏判断,只处理聊天请求。
(2)如果是聊天消息,展⽰在控制台。
通道的容器属性
Netty中的Channel通道类、HandlerContext上下⽂类。
AttributeMap接⼝只有⼀个attr()⽅法,接收⼀个类型的key,返回⼀个类型的value。
按照Javadoc,AttributeMap实现必须是线程安全的。 channel实现了该接⼝。
public interface AttributeMap {
<T> Attribute<T> attr(AttributeKey<T> key);
}
不是原始的key,⽽是⼀个key的包装类。保证了key的唯⼀性,在整个netty汇总,key必须唯⼀。
不是原始的value,⽽是value的包装类。完成两个重要操作:设置-SET,取值-GET。
AttributeKey的创建:
AttributeKey.valueOf(String)
session如何设置和读取创建完AttributeKey后,就可以通过通道完成key-value的设置和取值。
通过attr获取到Attribute,在设置值,常常是链式调⽤:
channel.attr(AttributeKey)
获取Attribute后设置value:
channel.attr(AttributeKey).set(会话实例)
取值:
ServerSession session = ctx.channel().attr(SESSION_KEY).get();
强调:AttributeKey⼀般定义为⼀个常量。
六、服务端
· Handler模块:客户端请求的处理。
LoginRequestHandler
(1)⾮登录请求数据包传递到流⽔线下⼀站
(2)创建ServerSession
[Session][1][sessionID] sessionID-uuid
[Session][2][channel] channel
(3)起异步任务:调度执⾏登录业务逻辑
为什么要再起异步任务,将handler和processer两个模块?
答:
在服务器端需要隔离EventLoop(Reactor)线程和业务线程。
业务线程处理时候,通常会涉及到⼀些⽐较耗时的处理。
如数据库操作,远程接⼝调⽤等。但是IO读写操作通常都是毫秒级。
也就是说,netty内部的IO操作和业务处理操作在时间上不在⼀个数量级。
netty的⼀个EventLoop实例会开启2倍CPU合数的内部线程。
通常情况下,⼀个netty服务器会有⼏万个连接通道。也就是说,这⼏个线程会负责⼏万个连接。
⼀个EventLoop中内部线程上任务是串⾏的。
如果⼀个业务处理器执⾏1000ms,最终结果是阻塞了其他⼏⼗万个连接的IO处理。会出现严重的性能问题。
如果隔离业务操作和EventLoop,如何实现?
答:
专门开辟⼀个独⽴的线程池,负责独⽴的异步任务处理队列。
对于耗时的业务操作封装成异步任务,并放⼊异步队列中去处理。
这样,服务端的性能会提升很多。
ChatRedirectHandler
(1)判断是否为聊天请求
(2)判断是否登录,登录后可发消息
(3)开启异步消息转发,由ChatRedirectProcesser完成消息转发。
(3)开启异步消息转发,由ChatRedirectProcesser完成消息转发。
· Processer模块:以异步⽅式完成请求的业务逻辑处理。
LoginProcesser
(1)密码验证,验证结果写⼊通道。
(2)验证通过,绑定服务端会话,加⼊在线⽤户列表。
--------------------
·从ProtoMsg中获取user信息[uid+devId+token+nickName+platform]
·[Session][3][user]
放⼊user->session
·[Session][4][通道绑定]
通道绑定会话:channel.attr(SESSION_KEY).set(this)
SessionMap加⼊SessionId:this
·设置服务端登录:isLogin = true
-
-------------------
ChatRedirectProcesser
(1)根据⽬标⽤户ID(userID),出所有的服务器端的会话列表(session)。
(2)为每⼀个会话转发⼀份消息。
注:由于⼀个⽤户可能会有对个会话,所以发所有会话。
· Session模块:管理⽤户与通道的绑定关系。
ServerSession
⼀、胶⽔类
每⼀个ServerSession对应⼀个客户端连接。
每⼀个ServerSession拥有⼀个Channel成员实例、⼀个User成员实例。
⼆、服务器会话
为了通道状态管理变得⽅便(连接channel和⽤户user),使⽤会话概念。
由于客户端和服务器分别有各⾃的通道,参数也不⼀致,因此使⽤两个会话类型:客户端会话,服务端会话。
三、导航关系
正向导航:会话-->通道
主要⽤于出站场景,通过会话将数据包写出到通道。
反向导航:通道-->会话
主要⽤于⼊站场景,通过通道获取会话,进⾏下⼀步业务处理。
四、唯⼀标识:sessionId
SessionMap
⼀、会话管理器
⼀台服务器需要接受⼏万/⼏⼗万的客户端连接。
每⼀条连接都对应⼀个ServerSession实例。
服务端需要对这些⼤量的ServerSession实例进⾏管理。
⼆、原理
内部有线程安全的ConcurrentHashMap的map。key:sessionId value:serversession
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论