netty 如何知道是客户端主动掉线,并且channelId 在同时时出现的,数据混乱问题

951 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


首先要知道netty 是多线程的。是基于Socket的。

1: 之前博主在netty 中用List 来存储channelId 并作唯一识别,但忽略了一点,List 是不安全的。 尤其是多线程环境下,会出现数据混乱的问题。

2: 出于安全考虑,又采取了Map 形式。如果只是用来存取channelId 肯定是没有问题。 但如果多个接口都去调取这个Map 呢? 似乎有所不妥。

3: 博主这边环境是一个外网的应用,去给内网推送数据。这边存取 channelId 也没有考虑去用什么缓存在存取,直接是static 共享。

解决方案:

连接时:

1:当有客户端连接时,就把客户端的channelId 记录下来。

2:建立连接,返回消息

断开时:

1:客户端主动断开服务器连接,关闭流。

2:断开连接

 /**
  * 当有客户端连接时,handlerAdded会执行,就把该客户端的通道记录下来,加入队列
  * 连接第1步
  * @param ctx
  * @throws Exception
  */
 @Override
 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
     Channel channel = ctx.channel();
     channels.add(channel);
     super.handlerAdded(ctx);
 }

 /**
  * 建立连接时,返回消息
  * 连接第2步
  * @param ctx
  * @throws Exception
  */
 @Override
 public void channelActive(ChannelHandlerContext ctx) throws Exception {
     Channel channel = ctx.channel();
     AttributeKey<String> host_channel_key = AttributeKey.valueOf("channel-host");
     Attribute<String> attr = channel.attr(host_channel_key);
     InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
     String host = socketAddress.getHostString();
     attr.set(host);
     log.debug("通道号:[{}],客户端:[{}]: 在线",channel.toString(), channel.remoteAddress());
     super.channelActive(ctx);

 }


/**
 * 客户端主动断开服务端的链接,关闭流
 * */
 @Override
 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
     Channel channel = ctx.channel();
     log.debug("通道号:[{}],客户端:[{}]: 离线",channel.toString(), channel.remoteAddress());
     super.channelInactive(ctx);
 }
 
 /**
  * 断开连接 第2步
  *
  * @param ctx
  * @throws Exception
  */
 @Override
 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
     Channel channel = ctx.channel();
     channels.remove(channel);
     super.handlerRemoved(ctx);
     ctx.channel().close();
 }

最重要的一步。

public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

去看 DefaultChannelGroup 类中 add 方法

image.png

先不管,它是不是多线程的。 就看是否满足我们能现在的需要。 Channel channel = ctx.channel(); channels.add(channel); 到此我们已经把 channelId 放到了该放的地方。

那我们在回归开始:netty 它到底是不是多线程的。 博主能力有限,感兴趣的可以自己去看看。