Netty(4)聊天室 |心跳


【这就是个 demo,实际IM比这复杂N倍 】

一、群聊系统

实现的核心是在 服务端的handler这里缓存一份Channel
只有这样,服务端才能将一个客户端的消息转给其他客户端。

这里使用了 ChannelGroup 这类,看它的doc 说明:

A thread-safe Set that contains open Channels and provides various bulk operations on them. Using 
ChannelGroup, you can categorize Channels into a meaningful group (e.g. on a per-service or per-state 
basis.) A closed Channel is automatically removed from the collection, so that you don't need to worry 
about the life cycle of the added Channel. A Channel can belong to more than one ChannelGroup.

提取要点:

  • ChannelGroup 缓存了channel,方便对channel 批量操作
  • 可以将channel 根据 “服务” OR “状态” 分组
  • 一个channel 能够属于不同的组
  • channel关闭的时候, ChannelGroup 会自动删除它

// 核心 【服务端】handler 的实现
public class GroupchatServerHandler extends SimpleChannelInboundHandler<String> {

	// 单例 
	private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);


	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		SocketAddress socketAddress = ctx.channel().remoteAddress();
		channelGroup.forEach(u -> {
			if (u != ctx.channel()) {
				u.writeAndFlush("[客户端]" + socketAddress + " 说:" + msg);
			} else {
				u.writeAndFlush("[自己] 说了:" + msg);
			}
		});
	}

	/**
	 * Gets called after the ChannelHandler was added to the actual context and it's ready to handle events.
	 */
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		channelGroup.add(ctx.channel());

		channelGroup.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + " 进入聊天室");
	}

	/**
	 * Gets called after the ChannelHandler was added to the actual context and it's ready to handle events
	 */
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		channelGroup.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + " 离开了聊天室");

		//NO NEED TO call remove() explictly
		//channelGroup.remove(ctx.channel());
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

二、单聊系统

单聊系统,消息也需要经过服务端的转发;因此服务端需要缓存用户状态,这样服务端才可以writeAndFlush给特定的用户。

三、心跳检测

实现一个心跳检测机制:

  • 服务器3秒没有读,提示读空闲
  • 服务器5秒没有写,提示写空闲
  • 服务器 7秒没有读OR写,提示读写空闲

// 这放出来 核心的 ChannelInitializer 代码。我们可以根据 读OR 写空闲情况,加上特定的业务逻辑,比如 读写空闲 1H+ 就关闭掉连接

private ChannelInitializer<SocketChannel> initialChannel() {
		return new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel ch) throws Exception {
				ChannelPipeline pipeline = ch.pipeline();
				/**
				 * readerIdleTime: 多久没读就发一个心跳包
				 * writerIdleTime:多久没写就发一个心跳包
				 * allIdleTime:多久没有读写就发一个心跳包
				 *
				 * IdleStateEvent 触发之后,就会传递给管道中的下一个 channelHandler.userHandlerTrigger
				 * 去处理
				 */
				pipeline.addLast(new IdleStateHandler(3, 5, 7, TimeUnit.SECONDS));

				// 这里加入一个自定义的 心跳handler
				pipeline.addLast(new ChannelInboundHandlerAdapter() {
					@Override
					public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
						if (evt instanceof IdleStateEvent) {
							IdleStateEvent event = (IdleStateEvent) evt;
							IdleState state = event.state();
							switch (state) {
							...
							}							}
						}
					}

				});
			}
		};
	}

不知道你也没有类似疑惑,为啥TCP已经心跳了,还要有一个自己实现一个心跳呢?
先来做个粗浅的认识:
看上去 KEEP_ALIVE 很美好,但其实服务端有时并不能准确获取到连接的状态。比如,客户端(手机)改成飞行模式了,连接终止只是客户端的,可能在服务端看来连接还是存在的。

四、

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
   本课程由《Netty 4核心原理作者》亲授。    在互联网分布式系统的推动下,Netty 作为一个能够支撑高性能、高并发的底层网络通信框架而存在。Netty 底层是基于 Java NIO 实现的,对 NIO 进行了非常多的优化,因此深受广大开发者尤其是一线大厂开发者的青睐。    作为一个 Java 开发者,如果没有研究过 Netty,那么你对 Java 语言的使用和理解可能仅仅停留在表面,会点 SSH,写几个 MVC,访问数据库和缓存,这些只是初级 Java 开发者做的事。如果你要进阶,想了解 Java 服务器的高阶知识,Netty 是一个必须要跨越的门槛。学会了 Netty,你可以实现自己的 HTTP 服务器、FTP 服务器、UDP 服务器、RPC 服务器、WebSocket 服务器、Redis 的 Proxy 服务器、MySQL 的 Proxy 服务器等。    如果你想知道 Nginx 是怎么写出来的,    如果你想知道 Tomcat 和 Jetty 是如何实现的,    如果你也想实现一个简单的 Redis 服务器,    ……    那么你应该好好研究一下 Netty,它们高性能的原理都是类似的。    因为 Netty 5.x 已被官方弃用,本课程内容基于 Netty 4 分析其核心原理,培养高级开发者自己“造轮子”的能力。本课程不仅讲述理论知识,还围绕能够落地的实战场景,开创手写源码的学习方式,使学习源码更加高效。本书的主要特色是首次提供了基于 Netty 手写 RPC 框架、基于 Netty 手写消息推送系统等实战案例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值