请不要付费,只是把历史笔记发布,包含专栏内容总结。
专栏总结1:基础网络相关
专栏总结2:数据结构和算法
专栏总结3:操作系统和计算机原理
专栏总结4:Linux和linux内核
专栏总结5:mysql相关
专栏总结6:redis相关专栏总结7:中间件Nginx、消息队列
专栏总结java1:类型和String、反射
专栏总结java2:集合
专栏总结java3:类接口相关
专栏总结java4:异常
专栏总结java5:线程/多线程并发
专栏总结java6:jvm
专栏总结java7:jdk
专栏总结java8:Socket编程 nio
专栏总结java9:MyBatis+hibernate专栏总结java10:Spring
专栏总结java11:Spring MVC
专栏总结java12:springboot
专栏总结java13:springcloud
专栏总结java14:dubbo
问题:
Socket编程 nio
NIO模型,select/epoll的区别,多路复用的原理
NIO是什么?适用于何种场景?
简述BIO,NIO的具体使用及原理
《Netty实战》和《Netty权威指南 第2版》笔记
一、netty是什么
Netty是一个NIO网络编程框架,快速开发高性能、高可靠性的网络服务器/客户端程序。 极大地简化了TCP和UDP等网络编程。是一个异步事件驱动的网络框架。
Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。
Netty对JDK自带的NIO的API进行封装,解决上述问题,主要特点有:
- 设计优雅,适用于各种传输类型的统一API阻塞和非阻塞Socket;基于灵活且可扩展的事件模型,可以清晰地分析关注点;高度可定制的线程模型-单线程,一个或多个线程池;真正的无连接数据报套接字支持
- 使用方便,详细记录的Javadoc,用户指南和示例;没有其他依赖项,JDK5(Netty3.x)或6 (Netty4.x) 就足够了
- 高性能,吞吐量更高,延迟更低;减少资源消耗;最小化不必要的内存复制
- 安全,完整的SSL/TLS和StartTLS支持
- 社区活跃,不断更新,社区活跃,版本迭代周期短,发现的Bug可以被及时修复,同时,更多的新功能会被加入。
Netty常见的使用场景如下:
- 互联网行业。在分布式系统中,各个节点之间需要远程服务调用,高性能的RPC框架必不可少,Netty作为异步高性能的通信框架,往往作为基础通信组件被这些RPC框架使用。典型的应用有:阿里分布式服务框架Dubbo的RPC框架使用Dubbo协议进行节点间通信,Dubbo协议默认使用Netty作为基础通信组件,用于实现各进程节点之间的内部通信
- 游戏行业。无论是手游服务端还是大型的网络游戏,Java语言得到了越来越广泛的应用。Netty作为高性能的基础通信组件,它本身提供了TCP/UDP和HTTP协议栈。非常方便定制和开发私有协议栈,账号登录服务器,地图服务器之间可以方便的通过Netty进行高性能的通信
- 大数据领域。经典的Hadoop的高性能通信和序列化组件Avro的RPC框架,默认采用Netty进行跨节点通信,它的Netty Service基于Netty框架二次封装实现。
二、Netty和Tomcat有什么区别?
Netty和Tomcat最大的区别就在于通信协议,Tomcat是基于Http协议的,他的实质是一个基于http协议的web容器,但是Netty不一样,他能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流,完成类似redis访问的功能,这就是netty和tomcat最大的不同。
有人说netty的性能就一定比tomcat性能高,其实不然,tomcat从6.x开始就支持了nio模式,并且后续还有APR模式——一种通过jni调用apache网络库的模式,相比于旧的bio模式,并发性能得到了很大提高,特别是APR模式,而netty是否比tomcat性能更高,则要取决于netty程序作者的技术实力了。
web容器选择:
- tomcat就是专门针对http服务器,tomcat从7开始默认就是nio的, 做web容器选择成熟tomcat。
- netty是一个网络组件,tcp,udp,http都可以弄,但是官方文档都是些hello wolrd级别的。如果你非常了解http结构,完全可以基于netty搞出一个比tomcat牛的http server。如果做tcp开发,netty不二之选!拿Netty去整Http服务器需要自己造轮子,而且轮子可能随时崩溃。
三、netty快速入门
1、引入Maven依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
2、服务器端:
package com.demo.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.nio.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
public class NettyServer {
public static void main(String[] args) {
// 创建mainReactor用来接收进来的连接
NioEventLoopGroup boosGroup = new NioEventLoopGroup();
// 创建工作线程组:用来处理已经被接收的连接,一旦bossGroup接收到连接,就会把连接信息注册到workerGroup上
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//服务端nio启动辅助类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap
.group(boosGroup, workerGroup) //组装NioEventLoopGroup
.channel(NioServerSocketChannel.class)//设置channel类型为NIO类型
.option(ChannelOption.SO_BACKLOG, 128) // // 设置连接配置参数:tcp最大缓存链接个数
.childOption(ChannelOption.SO_KEEPALIVE, true) //保持连接
.handler(new LoggingHandler(LogLevel.INFO)) // 打印日志级别
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
// 这里相当于过滤器,可以配置多个
ch.pipeline().addLast(new StringDecoder());
// ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
// @Override
// protected void channelRead0( ChannelHandlerContext ctx, String msg) {
// System.out.println("receive:" + msg);
// ctx.write("ok");//发送给客户端
// }
// });
// 自定义处理类
//注册OutboundHandler在前面 在channel队列中添加一个handler来处理业务:注册OutboundHandler
ch.pipeline().addLast(new ReponseHandler());
//注册InboundHandler
ch.pipeline().addLast(new ServerHandler());
}
});
//绑定端口,开始接收进来的连接:通过调用sync同步方法阻塞直到绑定成功
ChannelFuture cf = serverBootstrap.bind(8800).sync();
// 等待服务器socket关闭
cf.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
// 优雅退出,释放线程池资源
System.out.println("finally:" );
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static class ServerHandler extends ChannelInboundHandlerAdapter {
/**
* 收到数据时调用
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
System.out.println("ServerHandler:" + msg);
ctx.write(msg);
ctx.flush();
} finally {
// 抛弃收到的数据
//ReferenceCountUtil.release(msg);
}
// 通知执行下一个InboundHandler
//ctx.fireChannelRead(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelReadComplete");
super.channelReadComplete(ctx);
ctx.flush(); // 4
}
/**
* 当Netty由于IO错误或者处理器在处理事件时抛出异常时调用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
}
public static class ReponseHandler extends ChannelOutboundHandlerAdapter {
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("ChannelOutboundHandlerAdapter.read 发来一条消息\r\n");
super.read(ctx);
}
// 向client发送消息
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("ReponseHandler=========================write:");
String response = "I am ok!";
ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
encoded.writeBytes(response.getBytes());
ctx.write(encoded);
ctx.flush();
}