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编程 在任何时候都可能有大量的线程处于休眠状态,只是等待输入或者输出数据就绪,这可能算是一种资源浪费. 需要为每个线程的调用栈都分配内存,其默认值 ...
随机推荐
- LeetCode#160-Intersection of Two Linked Lists-相交链表
一.题目 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, listA = [4,1,8,4,5], l ...
- 2. node xlsx的使用
1. 使用xlsx模块 const xlsx = require('xlsx'); //excel async exportexcel() { let arrayData = [ ['姓名', '电话 ...
- 解决IE升级后必须以管理员运行的问题
很多网友可能都遇到过这样的问题,在ie升级后,无法打开,必须以管理员身份运行.今天我也遇到了这个问题.最终找到了解决办法. 1.Win + R 2.输入 regedit,定位到 HKEY_CURREN ...
- Git基本操作和使用
基本命令: git config git init git clone git remote git fetch git commit git rebase git push 本地基本操作: git ...
- linux的p0f检测,分析抓包信息
p0f是一个纯粹的被动指纹识别工具,它在不干涉双方通信的情况下,通过嗅探的方式来分析流经某一网卡的流量以达到指纹识别的目的 P0f是继Nmap和Xprobe2之后又一款远程操作系统被动判别工具.它支持 ...
- QString 转换成 wchar 的一个小陷阱
QString::toWCharArray(wchar_t * array) 其中 wchar_t * array 除了要分配内存之外,必须用 wmemset 初始化. 环境是 Visual Stud ...
- C++ Windows - How to get process path from its PID
出处 https://stackoverflow.com/questions/1933113/c-windows-how-to-get-process-path-from-its-pid 注意质疑(我 ...
- 为什么要你们现在要学习python
说学习python之前,我们先来聊聊其他的.我们都认为成功靠的是勤奋和努力,但是事实是只靠勤奋和努力是不一定会成功的,而且很大一部分都不会成功. 你有没有想过,同样是做企业,有些公司年收入百万,而腾讯 ...
- 在java中构建高效的结果缓存
文章目录 使用HashMap 使用ConcurrentHashMap FutureTask 在java中构建高效的结果缓存 缓存是现代应用服务器中非常常用的组件.除了第三方缓存以外,我们通常也需要在j ...
- 理解分布式一致性:Paxos协议之Multi-Paxos
理解分布式一致性:Paxos协议之Multi-Paxos Multi-Paxos without failures Multi-Paxos when phase 1 can be skipped Mu ...