什么是Netty

  • Netty是一个基于Java NIO的编写客服端服务器的框架,是一个异步事件框架。
  • 官网https://netty.io/

为什么选择Netty

由于JAVA NIO编写服务器的过程过于复杂且不易掌控,所以我们选择Netty框架进行开发。

  • 具有很高的的性能。
  • 且比NIO更容易编码和维护。
  • 实践者众多,Elastic Search,dubbo,Akka,grpc等等
  • 社区很成熟。

Netty的常用组件

  • EventLoopGroup 相当于Reactor线程组,常用NioEventLoopGroup
  • Channel 连接到网络套接字或能够进行I/O操作(如读、写、连接和绑定)的组件的连接。常用NioServerSocketChannel,NioSocketChannel,SocketChannel
  • Bootstrap/ServerBootstrap 辅助类
  • ChannelPipeline 处理或截取通道的入站事件和出站操作的通道处理程序列表
  • ChannelHandler 处理I/O事件或拦截I/O操作,并将其转发到其ChannelPipeline中的下一个处理程序。常用ChannelInboundHandlerAdapter和SimpleChannelInboundHandler,编码器,解码器。
  • ChannelFuture 异步操作使用。

Netty实现一个服务器

服务器代码:

/**
* @author monkjavaer
* @date 2019/7/18 14:56
*/
public class NettyServer {
private static Logger LOGGER = LoggerFactory.getLogger(NettyServer.class);
public static int PORT = 8080;
public static void connect(){
//配置两个服务端的NIO线程组,一个用于接收客服端的链接,另一个用于进行SocketChannel的网络读写。
//NioEventLoopGroup是一个处理I/O操作的多线程事件循环
//"boss":接收一个传入连接
EventLoopGroup boss = new NioEventLoopGroup();
//"worker" : 当boss接收连接并把接收的连接注册给worker,work就开始处理
EventLoopGroup worker = new NioEventLoopGroup();
try {
//ServerBootstrap是一个帮助类,可以设置服务器
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss,worker)
//NioServerSocketChannel用于实例化新通道来接收传入的连接
.channel(NioServerSocketChannel.class)
//配置日志
.handler(new LoggingHandler(LogLevel.INFO))
//ChannelInitializer用于配置新通道
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//通过ChannelPipeline添加处理类ChannelHandler
//通常有很多处理类,可以将这个内部类new ChannelInitializer提为一个独立的类
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new NettyServerHandler());
}
})
//ChannelOption和ChannelConfig可以设置各种参数
.option(ChannelOption.SO_BACKLOG, 128)
//option()用于接受传入连接的NioServerSocketChannel,childOption()用于父ServerChannel接受的通道
.childOption(ChannelOption.SO_KEEPALIVE, true); // Bind and start to accept incoming connections.
//异步地绑定服务器;调用 sync()方法阻塞等待直到绑定完成
ChannelFuture f = bootstrap.bind(PORT).sync();
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
} public static void main(String[] args) {
NettyServer.connect();
}
}
  • 首先创建两个NioEventLoopGroup线程组,一个用于接收客服端的链接,另一个用于进行SocketChannel的网络读写。
  • 创建一个服务器帮助类ServerBootstrap,将boss,worker两个线程组加入
  • 通过ServerBootstrap流式设置服务器
  • 设置通道为NioServerSocketChannel
  • 通过ChannelInitializer设置自定义处理器NettyServerHandler,并将他加入ChannelPipeline,这里用内部类简易实现,真实线上环境我们应该提取为相应的类。
  • 通过option和childOption设置TCP相关参数。
  • 异步地绑定服务器;调用 sync()方法阻塞等待直到绑定完成
  • 最后关闭相关资源

服务器处理类:

客户端的处理类和服务器类似。

/**
* ChannelHandler.Sharable 标注一个channel handler可以被多个channel安全地共享
* ChannelInboundHandlerAdapter实现了ChannelInboundHandler
* 回调事件处理类
*
* @author monkjavaer
* @date 2019/7/18 15:36
*/
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
private static Logger LOGGER = LoggerFactory.getLogger(NettyServerHandler.class); /**
* 新的连接被建立时调用
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOGGER.info("client {} connected.", ctx.channel().remoteAddress());
ctx.writeAndFlush(Unpooled.copiedBuffer("hello client!", CharsetUtil.UTF_8));
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
//获取缓冲区可读字节数
int readableBytes = byteBuf.readableBytes();
byte[] bytes = new byte[readableBytes];
byteBuf.readBytes(bytes);
LOGGER.info("readableBytes is{},server received message:{}", readableBytes, new String(bytes, StandardCharsets.UTF_8));
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
// ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
// .addListener(ChannelFutureListener.CLOSE);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOGGER.error("server exceptionCaught,{}",cause.getMessage());
ctx.close();
}
}
  • 自定义处理类继承自ChannelInboundHandlerAdapter
  • 重写我们需要的方法,channelActive(新的连接被建立时调用),channelRead(读取数据),channelReadComplete(读取最后的一条信息),exceptionCaught(发生异常时调用)

Netty实现一个客户端

客户端

/**
* @author monkjavaer
* @date 2019/7/18 17:17
*/
public class NettyClient {
private static Logger LOGGER = LoggerFactory.getLogger(NettyClient.class);
public static String IP = "127.0.0.1";
public static int PORT = 8080; public static void main(String[] args) {
EventLoopGroup client = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(client)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new NettyClientHandler());
}
}); ChannelFuture f = bootstrap.connect(IP,PORT).sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
client.shutdownGracefully();
}
}
}
  • 客户端这里只创建一个线程组即可
  • 帮助类这里使用Bootstrap
  • 设置通道为NioSocketChannel
  • 其他类容和服务器雷士
  • 和服务器建立连接

客户端处理类

/**
* @author monkjavaer
* @date 2019/7/18 17:26
*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
private static Logger LOGGER = LoggerFactory.getLogger(NettyServerHandler.class); /**
* 新的连接被建立时调用
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOGGER.info("server {} connected.", ctx.channel().remoteAddress());
ctx.writeAndFlush(Unpooled.copiedBuffer("hello server!", CharsetUtil.UTF_8));
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
//获取缓冲区可读字节数
int readableBytes = byteBuf.readableBytes();
byte[] bytes = new byte[readableBytes];
byteBuf.readBytes(bytes);
LOGGER.info("readableBytes is{},client received message:{}", readableBytes, new String(bytes, StandardCharsets.UTF_8));
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOGGER.error("server exceptionCaught,{}",cause.getMessage());
ctx.close();
}
}

【Netty】Netty简介及服务器客户端简单开发流程的更多相关文章

  1. 微信公众号PHP简单开发流程

    原文:微信公众号PHP简单开发流程 微信公众号开发分傻瓜模式和开发者模式两种,前者不要考虑调用某些接口,只要根据后台提示傻瓜式操作即可,适用于非专业开发人员. 开发模式当然就是懂程序开发的人员使用的. ...

  2. Struts1简单开发流程梳理

    共享数据的4种范围MVC设计模式JSP model1.JSP model2struts实现MVC机制(ActionServlet.Action)struts-config.xml ActionServ ...

  3. iOS产品开发流程

    iOS产品开发流程 a.产品经理做需求调研,确定产品需求,编写需求文档 b.产品人员完成产品原型 c.产品经理召开会议(产品,UI,UE,开发,测试,服务器) d.设计人员根据原型设计出一系列UI界面 ...

  4. RocketMQ客户端加载流程

     这节介绍RocketMQ客户端的启动流程,即Consumer和Producer的启动流程. 1. 客户端demo  首先先看下客户端的demo Producer: public class Sync ...

  5. Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

  6. Netty实现高性能IOT服务器(Groza)之精尽代码篇中

    运行环境: JDK 8+ Maven 3.0+ Redis 技术栈: SpringBoot 2.0+ Redis (Lettuce客户端,RedisTemplate模板方法) Netty 4.1+ M ...

  7. Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上

    前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...

  8. Netty源码分析之客户端启动过程

    一.先来看一下客户端示例代码. public class NettyClientTest { public void connect(int port, String host) throws Exc ...

  9. c#Socket服务器与客户端的开发(1)

    上个项目中用到了Socket通讯,项目中直接借助SuperSocket实现,但是我觉得这毕竟是一个我没接触过的东西,所以也顺便学习了一下原生socket的使用,做了一个socket服务器与客户端的开发 ...

随机推荐

  1. <input type="image"> 和 <img> 用法区别

    原文:<input type="image"> 和 <img> 用法区别 w3c定义如下: Image <input type="image ...

  2. ASP.NET MVC控制器Controller中参数

    前述文章参见:ASP.NET MVC控制器Controller 绪论 之前的控制器返回的均为常量字符串,接下来展示如何获取请求传来的参数,而返回"动态"的字符串. 可以在操作方法B ...

  3. Indy9的TIdFTPServer封装类

    在Delphi 7开发下有强大的Indy控件,版本为9,要实现一个FTP服务器,参考自带的例子,发现还要写很多函数,而且不支持中文显示文件列表等等.于是,自己改进封装了下,形成一个TFTPServer ...

  4. SQL数据库连接池与C#关键字return

    SQL数据库连接池: 先前做的一个Sharepoint项目,在上线后的不久,最近一直出现间歇性访问缓慢问题Sharepoint特性问题,并分析了其数据库服务器,发现所耗内存已经达到了97%. 所以断定 ...

  5. 解除.NET中虚拟路径的疑惑

    今天部署产品时,发现一个涉及到路径错误的bug,在开发环境下都OK,但是到了测试环境中却一直报错,经过一番排查,原来错误出在了HttpContext.Current.Server.MapPath这个方 ...

  6. redis INFO 解释

    以一种易于解释(parse)且易于阅读的格式,返回关于 Redis 服务器的各种信息和统计数值. 通过给定可选的参数 section ,可以让命令只返回某一部分的信息: server 部分记录了 Re ...

  7. 使用Nodejs实现实时推送MySQL数据库最新信息到客户端

    下面我们要做的就是把MySQL这边一张表数据的更新实时的推送到客户端,比如MySQL这边表的数据abc变成123了,那使用程序就会把最新的123推送到每一个连接到服务器的客户端.如果服务器的连接的客户 ...

  8. m3u8解析、转码、下载、合并

    m3u8解析.转码.下载.合并 现在网也上大多数视频需要下载都很麻烦,极少数是MP4,大多都是m3u8, 先说视频下载, pc端: 打开网页,点击视频播放,打开开发者工具,找到网络那一栏, 等整个网页 ...

  9. 创建一个简单的Django项目

    1.首先,启动pycharm,点击File->New Project,如下图所示. 2.在New Project对话框中,选择Django,在Location中设置项目路径以及项目名称,在App ...

  10. sentinel 集群流控原理

    为什么需要集群流控呢?假设需要将某个API的总qps限制在100,机器数可能为50,这时很自然的想到使用一个专门的server来统计总的调用量,其他实例与该server通信来判断是否可以调用,这就是基 ...