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设置脚本最大执行时间的三种方法 1.在php.ini里面设置 max_execution_time = 120; 2.通过PHP的ini_set函数设置 ini_set("max_ex ...
- LeetCode#160-Intersection of Two Linked Lists-相交链表
一.题目 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5], l ...
- selenium 窗口的切换
窗口切换需要用到一个关键词:句柄,每个窗口唯一的标识 获取句柄的方法:driver.getWindowHandle(); 下面的例子是点击京东页面,跳转到京东手机页面,然后关闭京东页面 driver. ...
- 使用dynamic 和MEF实现轻量级的 AOP 组件 (1)
转载https://www.cnblogs.com/niceWk/archive/2010/07/19/1780843.html AOP魔法 今天你AOP了吗?谈到AOP,总有一种神秘的感觉,人类对于 ...
- 彻底解决Python编码问题
1. 基本概念 字符集(Character set) 解释:文字和符合的总称 常见字符集: Unicode字符集 ASCII字符集(Unicode子集) GB2312字符集 编码方法(Encoding ...
- 2019-2020-1 20199303《Linux内核原理与分析》第八周作业
Linux如何启动并装载程序 理解编译链接的过程和ELF可执行文件格式 第一步:先编辑一个hello.c 第二步:生成预处理文件hello.cpp gcc -E -o hello.cpp hello. ...
- 【DNS域名解析命令】 nslookup
1. nslookup作用 nslookup用于查询DNS的记录,查询域名解析是否正常,在网络故障时用来诊断网络问题 nslookup - query Internet name servers in ...
- pynlpir.License过期问题解决方案
报错信息:pynlpir.LicenseError: Your license appears to have expired. Try running "pynlpir update&qu ...
- 【linux运维】rsync+inotify与sersync+rsync实时数据同步笔记
Rsync(remote sync)远程同步工具,通过rsync可以实现对远程服务器数据的增量备份通过,但rsync自身也有缺陷,同步数据时,rsync采用核心算法对远程服务器的目标文件进行对比,只进 ...
- 刚听完CSDN总裁蒋涛先生的学术报告
主题: 二十年程序人生和我的人才观 第一次参加所谓的"学术报告", 但感觉更多的是蒋总在跟我们分享他个人的成长经验. 按蒋总的话说, 他已经从2000年开始不碰怎么技术了, 所以个 ...