继续上篇完善 Netty + Redis + Websocket IM 分布式集群实现
MyWebsocketHandler 更新代码
/**
* 处理客户端与服务端之间的websocket业务
*
* @param ctx ctx
* @param frame frame
*/
private void handWebsocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// 判断是否是关闭websocket的指令
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), ((CloseWebSocketFrame) frame).retain());
log.debug("接收到关闭websocket的指令");
}
// 判断是否是ping消息
if (frame instanceof PingWebSocketFrame) {
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
log.debug("接收到ping消息");
return;
}
// 判断是否是二进制消息,如果是二进制消息,则抛出异常
if (!(frame instanceof TextWebSocketFrame)) {
log.error("目前不支持二进制消息");
throw new UnsupportedOperationException("【" + this.getClass().getName() + "】不支持的消息");
}
// 获取客户端向服务端发送的消息
String requestStr = ((TextWebSocketFrame) frame).text();
log.debug("服务端收到客户端的消息: {}", requestStr);
if (StringUtil.isNullOrEmpty(requestStr)){
return;
}
// 发布到redis 订阅列表中,进行广播
String keychannel = ctx.channel().id().asLongText();
//是否第一次连接上来
if (requestStr.startsWith("connect:")){
String udfromkey = requestStr.substring(requestStr.indexOf(":")+1);
List ufromChannelList = NettyConfig.LOCALCHANNELLISTMAP.get(udfromkey);
if (ufromChannelList == null || ufromChannelList.isEmpty()){
ufromChannelList = new ArrayList<>();
}
Long flag = 1L;///是否存在
for (String channel : ufromChannelList) {
if (channel.equals(keychannel)){
flag = 0L;
break;
}
}
if (new Long(1L).equals(flag)){
ufromChannelList.add(keychannel);
NettyConfig.LOCALCHANNELLISTMAP.put(udfromkey,ufromChannelList);
}
NettyConfig.LOCALCHANNELMAP.put(keychannel,udfromkey);
ChannelId id = ctx.channel().id();
byte[] channelBytes = BeanUtil.enSeri(id);
NettyConfig.LOCALCHANNELBYTES.put(keychannel+"Id",channelBytes);
return;
}
RequestBean obj = JSONObject.parseObject(requestStr,RequestBean.class);
String udfromkey = "";
if (!StringUtil.isNullOrEmpty(obj.getUfrom())){
udfromkey = "ufrom:" + obj.getUfrom();
}else if (StringUtil.isNullOrEmpty(obj.getDfrom())){
udfromkey = "dfrom:" + obj.getDfrom();
}
NettyConfig.LOCALCHANNELMAP.put(keychannel,udfromkey);
List ufromChannelList = NettyConfig.LOCALCHANNELLISTMAP.get(udfromkey);
if (ufromChannelList == null || ufromChannelList.isEmpty()){
ufromChannelList = new ArrayList<>();
}
Long flag = 1L;///是否存在
for (String channel : ufromChannelList) {
if (channel.equals(keychannel)){
flag = 0L;
break;
}
}
if (new Long(1L).equals(flag)){
ufromChannelList.add(keychannel);
NettyConfig.LOCALCHANNELLISTMAP.put(udfromkey,ufromChannelList);
}
String udtokey = "";
if (!StringUtil.isNullOrEmpty(obj.getUfrom())){
udtokey = "ufrom:" + obj.getUto();
}else if (StringUtil.isNullOrEmpty(obj.getDfrom())){
udtokey = "dfrom:" + obj.getDto();
}
JedisUtil.set(udtokey,requestStr);
JedisUtil.pushMsg(udtokey);
}
/**
* 客户端与服务端创建连接的时候调用
*
* @param ctx ctx
* @throws Exception Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 将channel添加到channel group中
NettyConfig.GROUP.add(ctx.channel());
NettyConfig.LOCALCHANNELMAP.put( ctx.channel().id().asLongText(),"1");//存在,并且在线
log.info("客户端与服务端连接开启...");
}
/**
* 客户端与服务端断开连接的时候调用
*
* @param ctx ctx
* @throws Exception Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// 从channel group中移除这个channel
NettyConfig.GROUP.remove(ctx.channel());
NettyConfig.LOCALCHANNELMAP.remove(ctx.channel().id().asLongText());// 不存在,离线
log.info("客户端与服务端关闭连接...");
}
RedisMsgPubSubListener 更新部分
if (StringUtil.isNullOrEmpty(udto)){
return;
}
String msg = JedisUtil.get(udto);
if (StringUtil.isNullOrEmpty(msg)){
return;
}
List fromchannelList = NettyConfig.LOCALCHANNELLISTMAP.get(udto);
if (fromchannelList == null || fromchannelList.isEmpty()){
return;
}
for (String channelId : fromchannelList) {
try {
String ufrom = NettyConfig.LOCALCHANNELMAP.get(channelId);
if (StringUtil.isNullOrEmpty(ufrom)){
continue;
}
byte[] channelBytes = NettyConfig.LOCALCHANNELBYTES.get(channelId + "Id");
ChannelId id = BeanUtil.deSeri(channelBytes,DefaultChannelId.class);
if (id == null){
continue;
}
Channel channel = NettyConfig.GROUP.find(id);
if (channel != null){
String responseStr = new Date().toString() + channel.id() + " ===>>> " + msg;
TextWebSocketFrame tws = new TextWebSocketFrame(responseStr);
channel.writeAndFlush(tws);
}
}catch (Exception e){
log.error("writeAndFlush error ",e);
}
}
ws123.html
socket.send("connect:ufrom:"+userNo)
var userNo="123";
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:8989/ws");
socket.onmessage = function (ev) {
var ta = document.getElementById('responseContent');
ta.value += ev.data + "\r\n";
};
socket.onopen = function (ev) {
var ta = document.getElementById('responseContent');
ta.value = "您当前的浏览器支持WebSocket, 请进行后续操作\r\n";
socket.send("connect:ufrom:"+userNo)
};
socket.onclose = function (ev) {
var ta = document.getElementById('responseContent');
ta.value = "WebSocket连接已经关闭\r\n";
};
socket.onerror = function (ev) {
var ta = document.getElementById('responseContent');
ta.value = ev.data + "WebSocket连接异常\r\n";
};
} else {
alert("您的浏览器不支持WebSocket");
}
var toUserNo="124";
function send(message) {
if (!window.WebSocket) {
return;
}
if (socket.readyState === WebSocket.OPEN) {
var json = "{" +
"\"ufrom\":\""+userNo+"\"," + // ufrom 来至用户
"\"dfrom\":\"\"," + // dfrom 来至医生
"\"uto\":\""+toUserNo+"\"," + // uto 送达用户
"\"dto\":\"\"," + // dto 送达医生
"\"msg\":\""+message+"\"" +
"}"
socket.send(json);
} else {
alert("WebSocket连接建立失败, 请重试");
console.log(socket.readyState)
}
}