netty(八)WebSocket心跳

tcp心跳模型, 

TCP新手误区–心跳的意义

netty(六)WebSocket实践

的基础上:

 

主要修改:

TextWebSocketFrameHandler文件:

public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<String> {

    private static final String SPLIT = ":\t";

    private static final ChannelGroup group = new DefaultChannelGroup("ChannelGroups", GlobalEventExecutor.INSTANCE);
    private static final ConcurrentHashMap<String, Channel> userChannel = new ConcurrentHashMap<String, Channel>();

    private static String getOnine() {
        。。。。
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {

            // 移除性能更加
            ctx.pipeline().remove(HttpRequestHandler.class);
            String userName = ctx.channel().attr(HttpRequestHandler.key).get();
            Channel old = userChannel.put(userName, ctx.channel());
            if(old != null) {
                group.remove(old);
                System.out.println(old.attr(HttpRequestHandler.key).get() + SPLIT + "[切换设备]");
                ChannelFuture channelFuture = old.writeAndFlush("您的账户在其它地方登陆");
                channelFuture.addListener(ChannelFutureListener.CLOSE);
            }

            ctx.writeAndFlush("-=====登录成功=====-");

            String up = userName + SPLIT + "[上线]";
            System.out.println(up);
            group.writeAndFlush(up);

            group.add(ctx.channel());

            String online = getOnine();
            System.out.println(online);
            group.writeAndFlush(online);

        }else if (evt instanceof IdleStateEvent) {
            // 2*4+1 s内读空闲时,关掉连接,表示客户端不可见了
            IdleStateEvent evnet = (IdleStateEvent) evt;
            if (evnet.state().equals(IdleState.READER_IDLE)) {
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

  

    @Override
    public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 这一段也是错的,书上因为是直接write,因此要retain,这里已经新建了String实例,所以retain会造成内存泄漏
//        String send = ctx.channel().attr(HttpRequestHandler.key).get() + SPLIT + msg.retain().text();
//        System.out.println(send);
//        group.writeAndFlush(new TextWebSocketFrame(send));

        if("HeartBeat".equals(msg)) {
            // 心跳只给自己发
            ctx.writeAndFlush(msg);
        } else {
            // 聊天发给所有人
            String send = ctx.channel().attr(HttpRequestHandler.key).get() + SPLIT + msg;
            System.out.println(send);
            group.writeAndFlush(send);
        }
    }

  

WebSocketServerInitializer文件:

        // 读空闲5秒激发
        ch.pipeline().addLast(new IdleStateHandler(9, 0, 0, TimeUnit.SECONDS));

  

前端:

	
			function WSonClose() {
		       	   ws = null;
		           alert("连接关闭。");

		       };
	 		var heart = null;
		 	var receiveTimeOut = 4000;
		 	var lastTime = false;
		       function WSonMessage(event) {     
		           $("#board").val(event.data + "\n" + $("#board").val());   
		           
		           // 收到消息保留4秒,4秒后消灭
		           lastTime = true;
		           setTimeout(function(){
			            lastTime = false;
			        }, receiveTimeOut);

		           	// 收到消息后4秒发送一次心跳,要求服务器channel一旦连接就发一条消息过来
		           	clearTimeout(heart);
		       		heart = setTimeout(function(){
			            ws.send("HeartBeat");
			        }, receiveTimeOut);

		       		// 5 秒后查看
			        checkHeart();

		       };

		       function checkHeart() {
		       		setTimeout(function(){
			        	// 5s后查看
			        	if(!lastTime) {
			        		alert('与服务器断开连接了');
			        		ws.close();
			        	}
			        }, receiveTimeOut + 1000)
		       }

  

实践:

2台服务器,A放前端  B放后端 

客户端发4次心跳后,拔掉网线

服务端5秒后下线

客户端:

 

 

前端代码有巨大问题:改为:

		       	var lastTime = new Date().valueOf();
				function WSonOpen() {
		           
		       		setInterval(function(){
		       			console.log('send - ' + new Date().valueOf());
			            ws.send("HeartBeat");

			        }, 4000);

		           setTimeout(function(){
			            setInterval(function(){
			            	var now = new Date().valueOf();
			            	console.log('chek - ' + now);
				        	if((now - lastTime) > 8000) {
				        		alert('与服务器断开连接了');
				        		ws.close();
				        	}
				        }, 4000);
			        }, 1000);
		       };
		 		
		       function WSonMessage(event) {   

		           lastTime = new Date().valueOf();
		           console.log('get  - ' + lastTime);

			        if(event.data == 'HeartBeat') 
		           		$("#heart").val("=" + $("#heart").val());   
		           	else if(-1 != event.data.indexOf("[在线用户]"))
		           		$("#online").val(event.data);   
		           	else 
		           		$("#board").val(event.data + "\n" + $("#board").val());  

		       };

  

经验值服务端9秒未收到数据,断开连接,客户端4s发一次ping,客户端9秒内,连续2次未收到pong,切断连接

posted on 2018-09-07 18:07  silyvin  阅读(985)  评论(0)    收藏  举报