Netty入门一:何为Netty
先了解java的网络编程
Netty为何支持高并发
netty是基于java的nio非阻塞通信,而原始的阻塞通信无法满足高并发。下面我们通过两幅图来简要说明
BIO:

这种模式下一个线程处理一个连接,当某个连接阻塞处于等待状态时该线程也处于阻塞等待状态,而我们的机器一共支持的线程数是有限的,如:你的机器只支持30000个线程,那么它最大的并发量也就只有30000。
NIO:

在NIO模式下,我们看到一个线程并不是单一的去处理某一个连接。事实是这样的:先去建立连接,不管建立多少个,建立好之后都交给一个叫selector的处理器,这个处理器的作用就是循环遍历你建立的所有的连接,当遍历到某个连接时,它就判断这个连接是否处于阻塞等待状态,如果处于阻塞等待状态则什么都不做让它继续去等待,继续判断下一个;如果判断到某个连接已经建立通信,则将该连接交给thread去执行通信,这样我们的一个thread就不用专门去为一个连接服务,当某个连接阻塞时我们的线程仍然可以处理其他的连接;即,此时我们的一个线程可以处理多个连接,这就是为什么Netty支持高并发的原因
netty为何通讯快
netty传输速度快的主要原因是NIO的另一个特点:零拷贝。什么是0拷贝呢?我们先说说JAVA的内存机制,JAVA的内存分为5大块:栈、堆、方法区、本地方法区和寄存器。而这中间最重要的一块就是堆,也就是java存放对象的地方。当我们进行通信的时候,数据从客户端传输过来本来是先要将数据拷贝到Socket的缓冲区,再将这些数据拷贝到堆内存,再供程序去使用,当数据量较大的时候平凡的大量的数据拷贝就会占用大量的资源。而NIO的零拷贝是在java的内存里面又分配出一块新的内存专门用来存储客户端传过来的数据,也就是数据不经过socket的缓冲区和堆内存,直接到新开辟的这块内存供程序使用,使用的时候Netty为其提供了专门的Api:ByteBuf。由于数据直接从客户端到ByteBuf,应用程序直接从ByteBuf那里取数据,中间做到了零拷贝,所以netty的传输速度比较快。
netty为何封装好
阻塞I/O
public class BioServer {
public void serve(int port) throws IOException {
ServerSocket socket = new ServerSocket(8088); //1创建服务端
try {
for (;;) {//死循环用来不断监听客户端
Socket clientSocket = socket.accept(); //2监听客户端,如果客户端未建立则程序阻塞挂起,处于等待状态
System.out.println("Accepted connection from " + clientSocket);
new Thread(new Runnable() { //3创建线程处理已经建立的线程
@Override
public void run() {
OutputStream out;
try {
out = clientSocket.getOutputStream();//从客户端通道中获取输出流对象
out.write("Hi!\r\n".getBytes(Charset.forName("UTF-8"))); //4写数据到客户端
out.flush();
clientSocket.close(); //
} catch (IOException e) {
e.printStackTrace();
try {
clientSocket.close();
} catch (IOException ex) {
// ignore on close
}
}
}
}).start(); //
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO
public class NioServer {
public void serve(int port) throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);//默认就是非阻塞
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address); //1
Selector selector = Selector.open(); //2
serverChannel.register(selector, SelectionKey.OP_ACCEPT); //3注册Selector监听客户端连接 还有OP_CONNECT、OP_READ、OP_WRITE等事件
final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());//将数据格式化成ByteBuf格式
for (;;) {
try {
selector.select(); //4
} catch (IOException ex) {
ex.printStackTrace();
// handle exception
break;
}
Set<SelectionKey> readyKeys = selector.selectedKeys(); //5获取要监听的事件
Iterator<SelectionKey> iterator = readyKeys.iterator(); //创建迭代器
while (iterator.hasNext()) {
SelectionKey key = iterator.next();//遍历到某个事件
iterator.remove();
try {
if (key.isAcceptable()) { //6是否是客户端访问事件
ServerSocketChannel server =
(ServerSocketChannel)key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE |
SelectionKey.OP_READ, msg.duplicate()); //7
System.out.println(
"Accepted connection from " + client);
}
if (key.isWritable()) { //8 是否是写事件
SocketChannel client =
(SocketChannel)key.channel();
ByteBuffer buffer =
(ByteBuffer)key.attachment();
while (buffer.hasRemaining()) {
if (client.write(buffer) == 0) { //9
break;
}
}
client.close(); //10
}
} catch (IOException ex) {
key.cancel();
try {
key.channel().close();
} catch (IOException cex) {
// 在关闭时忽略
}
}
}
}
}
}
Netty
public class NettyServer {
public void server(int port) throws Exception {
final ByteBuf buf = Unpooled.unreleasableBuffer(
Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));
EventLoopGroup group = new OioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); //
b.group(group) //
.channel(OioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {//
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { //
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);//
}
});
}
});
ChannelFuture f = b.bind().sync(); //
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync(); //
}
}
}
从代码量上来看,Netty就已经秒杀传统Socket编程了,但是有些概念可能不是很明确,在这里给大家介绍一下Netty的一些重要概念,让大家更理解Netty。

- Channel,表示客户端和服务端建立的一次通信连接
- ChannelHandler,处理业务逻辑的处理器。
- ChannelHandlerContext,传输处理过程中的业务数据。
- ChannelPipeline,用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
ByteBuf:
ByteBuf是一个存储字节的容器,最大特点就是使用方便,它有自己的读索引和写索引,方便你对整段字节缓存进行读写,也支持get/set,方便你对其中每一个字节进行读写,他的数据结构如下图所示:

Netty入门一:何为Netty的更多相关文章
- Netty入门教程——认识Netty
什么是Netty? Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是一个广泛使用的 Java 网络编程框架(N ...
- Netty入门教程:Netty拆包粘包技术讲解
Netty编解码技术是什么意思呢?所谓的编解码技术,说白了就是java序列化技术.序列化有两个目的: 1.进行网络传输2.对象持久化 虽然我们可以使用java进行序列化,Netty去传输.但是java ...
- 深入了解Netty【六】Netty工作原理
引言 前面学习了NIO与零拷贝.IO多路复用模型.Reactor主从模型. 服务器基于IO模型管理连接,获取输入数据,又基于线程模型,处理请求. 下面来学习Netty的具体应用. 1.Netty线程模 ...
- (入门篇 NettyNIO开发指南)第三章-Netty入门应用
作为Netty的第一个应用程序,我们依然以第2章的时间服务器为例进行开发,通过Netty版本的时间服务报的开发,让初学者尽快学到如何搭建Netty开发环境和!运行Netty应用程序. 如果你已经熟悉N ...
- netty 入门(一)
netty Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更确切的讲是一个组件,没有那么复杂. 例子 一 Discard服务器端 我们 ...
- Netty入门之客户端与服务端通信(二)
Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...
- Netty入门之HelloWorld
Netty系列入门之HelloWorld(一) 一. 简介 Netty is a NIO client server framework which enables quick and easy de ...
- Netty入门
一.NIO Netty框架底层是对NIO的高度封装,所以想要更好的学习Netty之前,应先了解下什么是NIO - NIO是non-blocking的简称,在jdk1.4 里提供的新api,他的他的特性 ...
- netty入门(一)
1. netty入门(一) 1.1. 传统socket编程 在任何时候都可能有大量的线程处于休眠状态,只是等待输入或者输出数据就绪,这可能算是一种资源浪费. 需要为每个线程的调用栈都分配内存,其默认值 ...
随机推荐
- [php] 猴子偷桃
<?php /* 10:五只猴子采得一堆桃子,猴子彼此约定隔天早起后再分食. 不过,就在半夜里,一只猴子偷偷起来,把桃子均分成五堆后, 发现还多一个,它吃掉这桃子,并拿走了其中一堆.第二只猴子醒 ...
- EF-相关查询(逐渐完善)
linq查询方式 多条件查询 内连接 左连接 可以执行sql含事务
- CentOS 使用中问题记录
⚠️使用yum提示Error: rpmdb open failed的解决方案 清除原rpmdb文件,这一步可能不用操作,直接进行第2步 # rm -f /var/lib/rpm/__db.* 重建rp ...
- solr管理集合
其实完全版的管理,在web页面上就有. 同时,在官网文档上,也有:https://lucene.apache.org/solr/guide/6_6/coreadmin-api.html#CoreAdm ...
- 关于如何在Linux上使用Nugix反向代理部署net core3.1项目
本文意在教大家如何在Linux上部署net core web项目,本人通过实践已经成功可以通过外网访问我部署在阿里云服务器上的站点. 一:需要用到的东西如下: 1:一个基于net core框架下的we ...
- Tidyverse|数据列的分分合合,爱恨情仇
Tidyverse|数据列的分分合合,爱恨情仇 本文首发于“生信补给站”Tidyverse|数据列的分分合合,一分多,多合一 TCGA数据挖掘可做很多分析,前期数据“清洗”费时费力但很需要. 比如基因 ...
- PHP Callable强制指定回调类型的方法
如果一个方法需要接受一个回调方法作为参数,我们可以这样写 <?php function dosth($callback){ call_user_func($callback); } functi ...
- php 常量的使用
我们来看下直接的例子 <?php //定义常量 //常量不可被删除 //常量一旦被定义,就无法重新置换 //常量一旦定义,就不能对他第二次定义,否则会报错! define('MYCONSTANT ...
- java list随机截取(洗牌)
public void solution(){ List<Integer> givenList = Arrays.asList(1, 2, 3,4,5,6); Collections.sh ...
- java中functional interface的分类和使用
目录 简介 Functional Interface Function:一个参数一个返回值 BiFunction:接收两个参数,一个返回值 Supplier:无参的Function Consumer: ...