简介:
Netty 是一套异步事件驱动的网络应用程序框架,支持快速开发可维护、高性能、面向协议的服务器和客户端。Netty 中涵盖包括网络通讯、多线程处理和并发等多个领域的专业知识,并优雅的将这些知识组织和处理。
重要
本例中,所有消息处理均采用模拟处理方式,不涉及实际实现!!!
规则:推送消息必须为 email|内容、text|内容、hi|内容 … …
消息扩展采用工厂模式
消息缓冲机制:使用Netty里的ChannelOutboundBuffer类,通过给它配置一个高水位线和低水位线。
当buffer的大小超过高水位线的时候对应channel的isWritable就会变成false,当buffer的大小低于低水位线的时候,isWritable就会变成true。应用判断isWritable,如果是false就不再写数据了。高水位线和低水位线是字节数,默认高水位是64K,低水位是32K,我们可以根据我们的应用需要支持多少连接数和系统资源进行合理规划。
基础概念:
Netty 中的几个基础知识点
- 选择器
- Channel
- EventLoop
- 回调
- Future
- 事件和 ChannelHandler
Netty 中的 Socket 参数
- ChannelOption.SO_BACKLOG
BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1,Java将使用默认值50。
- ChannelOption.SO_KEEPALIVE
是否启用心跳保活机制。在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)并且在两个小时左右上层没有任何数据传输的情况下,这套机制才会被激活。
- ChannelOption.TCP_NODELAY
在TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。这里就涉及到一个名为Nagle的算法,该算法的目的就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。TCP_NODELAY就是用于启用或关于Nagle算法。如果要求高实时性,有数据发送时就马上发送,就将该选项设置为true关闭Nagle算法;如果要减少发送次数减少网络交互,就设置为false等累积一定大小后再发送。默认为false。
爬坑记录
- 异步处理,流控先行
与异步相比,同步有天然的负反馈机制,也就是如果后端慢了,前面也会跟着慢起来,可以自动的调节。但是异步就不同了,异步就像决堤的大坝一样,洪水是畅通无阻。如果这个时候没有进行有效的限流措施就很容易把后端冲垮。如果一下子把后端冲垮倒也不是最坏的情况,就怕把后端冲的要死不活。这个时候,后端就会变得特别缓慢,如果这个时候前面的应用使用了一些无界的资源等,就有可能把自己弄死。
- 连接超时
- 在不同的线程里使用 PooledByteBufAllocator 分配和回收
项目扩展
我对于 ByteBuf 还没有深入的理解,后续补充吧(ByteBuf——Netty 的数据容器 )… …
消息处理中心 Demo
项目用于搭建一个类似于在线通讯的消息推送中心(可通过简单的改变消费者,实现即时通讯)。
消息中心为服务端。支持各种消息发送,提供友好接口可支持消息种类扩充
- 服务端
// Server.java
package com.archer.server;
import com.archer.init.Initializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class Server {
private static int port;
public Server(int port) {
this.port = port;
}
public static void run() throws InterruptedException {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new Initializer())
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 64 * 1024)
.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("服务器启动了!");
future.channel().closeFuture().sync();
} finally {
worker.shutdownGracefully();
boss.shutdownGracefully();
System.out.println(