Netty + Redis + Websocket IM 分布式集群实现 ---用户多端登陆消息推送

继续上篇完善 Netty + Redis + Websocket IM 分布式集群实现 

Netty + Redis + Websocket IM 分布式集群实现 ---用户多端登陆消息推送_第1张图片

 

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)
            }
        }

 

你可能感兴趣的:(java)