一、前言

  在简单学习了Netty中的组件后,接着学习Netty中数据的传输细节。

二、传输  

  2.1 传输示例

  Netty中的数据传输都是使用的字节类型,下面通过一个实例进行说明,该实例中服务器接受请求,然后向客户端发送一个Hi,最后关闭连接。下面是不同方式的实现。

  1. OIO方式

  OIO与NIO对应,使用阻塞式的IO处理,其服务端代码如下  

package com.hust.grid.leesf.chapter4;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset; public class PlainOioServer { public void serve(int port) throws IOException {
final ServerSocket socket = new ServerSocket(port);
try {
for (;;) {
final Socket clientSocket = socket.accept();
System.out.println("Accepted connection from: " + clientSocket); new Thread(new Runnable() {
@Override
public void run() {
OutputStream out;
try {
out = clientSocket.getOutputStream();
out.write("Hi!\r\n".getBytes(Charset.forName("UTF-8")));
out.flush();
clientSocket.close(); } catch (IOException e) {
e.printStackTrace();
try {
clientSocket.close();
} catch (IOException ex) {
// ignore on close
}
}
}
}).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

OIO

  说明:其中,在for循环中会不断的去监听是否有新请求到达,当有请求到达后,初始化一个新的线程去处理,完成向客户端发送Hi字符串,最后关闭连接。使用OIO方式的性能较差,扩展性也不好,需要使用异步方式处理。

  2. NIO方式

package com.hust.grid.leesf.chapter4;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set; public class PlainNioServer {
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);
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
for (;;) {
try {
selector.select();
} catch (IOException ex) {
ex.printStackTrace();
// handle exception
break;
}
Set<SelectionKey> readyKeys = selector.selectedKeys(); //
Iterator<SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) { //
ServerSocketChannel server =
(ServerSocketChannel)key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE |
SelectionKey.OP_READ, msg.duplicate()); //
System.out.println(
"Accepted connection from " + client);
}
if (key.isWritable()) { //
SocketChannel client =
(SocketChannel)key.channel();
ByteBuffer buffer =
(ByteBuffer)key.attachment();
while (buffer.hasRemaining()) {
if (client.write(buffer) == 0) { //
break;
}
}
client.close(); //
}
} catch (IOException ex) {
key.cancel();
try {
key.channel().close();
} catch (IOException cex) {
// ignore on close
}
}
}
}
}
}

NIO

  说明:NIO方法使用了Selector和Channel等组件,使用Selector来处理多个Channel,其代码与OIO代码几乎是完全不相同。

  3. Netty的OIO方式

  当使用Netty框架处理时,并且采用OIO的方式,其代码如下 

package com.hust.grid.leesf.chapter4;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.oio.OioServerSocketChannel; import java.net.InetSocketAddress;
import java.nio.charset.Charset; public class NettyOioServer { 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的OIO

  可以看到上述代码很多都是和之前示例中使用的代码相同,再来看看在Netty框架下使用NIO时的处理方式。

  4. Netty的NIO方式  

package com.hust.grid.leesf.chapter4;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import java.net.InetSocketAddress;
import java.nio.charset.Charset; public class NettyNioServer { public void server(int port) throws Exception {
final ByteBuf buf = Unpooled.unreleasableBuffer(
Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));
NioEventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.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的NIO

  可以看到Netty框架下的NIO和OIO的代码基本相同。

  2.2 传输细节

  传输的核心是Channel接口,其继承结构图如下所示

  

  其中,Channel继承了AttributeMap和Comparable接口,其包含ChannelPipeline和ChannelConfig两个实例,ChannelConfig包含了所有的配置信息,ChannelPipeline包含了所有的ChannelHandler实例,其中用于存放用户的处理逻辑。典型的ChannelHandler用法如下

    · 将数据类型进行转化

    · 提供异常通知

    · 提供Channel变为活动或非活动的通知

    · 提供当Channel在EventLoopGroup中注册或者注销时的通知

    · 提供用户定义事件的通知

  Netty中的Channel实现是线程安全的,所以在多线程环境中可安全使用。

  2.3 传输方案

  Netty提供了多种传输方案,你可根据应用的不同选择合适的传输方案。

  1. NIO-非阻塞型I/O

  NIO提供了完全异步的IO实现,其使用基于选择器的API,选择器的核心概念是将其作为注册表,当通道的状态变化时会接受到通知,可能有的变化状态如下

    · 一个新通道被接受并已准备好

    · 一个通道的连接已经完成

    · 一个通道已经有准备好读取的数据

    · 一个通道可以写入数据

  当应用程序对状态的变化做出反应后,会重置选择器并重复处理,根据不同的状态给出不同的响应,选择操作有如下四种类型OP_ACCEPT 、OP_CONNECT、OP_READ 、OP_WRITE,其中选择器的处理流程如下图所示

  

  2. Epoll-Linux的本机非阻塞传输

  Netty可在任何系统上运行,但对于不同的系统会有不同的折中,Linux系统中的epoll具有高可扩展的I/O的事件通知,Linux上的JDK的NIO则是基于epoll,当使用epoll取代NIO时,可以使用Netty中的EpollEventLoopGroup取代NioEventLoopGroup,使用EpollServerSocketChannel.class取代NioServerSocketChannel.class。

  3. OIO-阻塞型I/O

  Netty的OIO是一种妥协方案,其使用JAVA中原生态的旧的API,其是同步阻塞的。在java.net的API中,通常使用一个线程接受来自指定端口的请求,当创建一个套接字时,就会创建一个新的线程来进行处理,其处理流程图如下图所示

  

  4. 在JVM内进行通信的本地传输

  Netty提供了在同一个JVM中的客户端与服务端之间的异步通信,在此传输中,与服务器通道相关联的SocketAddress不绑定到物理网络地址,相反,当服务器运行时,其存储在注册表中,关闭时取消注册。因为传输不能接受真正的网络流量,所以它不能与其他传输实现互操作。

  5. 嵌入式传输

  Netty还提供了一个额外的传输,其可以将ChannelHandler作为帮助类嵌入其他的ChannelHandler中,以这种方式,你无需修改其内部代码便能扩展ChannelHandler的功能。

  2.4 传输示例

  并非所有的传输都支持所有的传输协议,下表是传输方式与传输协议之间的关系

  

  而对于不同的应用,可根据下表选择合适的传输方式

  

三、总结

  本篇博文讲解了Netty中的传输细节,了解了多种不同的传输方式,以及其和不同传输协议之间的关系,也谢谢各位园友的观看~

【Netty】Netty传输的更多相关文章

  1. [Netty] - Netty IN ACTION(导言)

    最近没什么事儿做,刚好看到有需要网络编程的知识,java中有NIO和IO两种不同的方式,但是NIO的编写比较麻烦,刚好找到一个成熟的网络框架Netty.接下来的一个月就准备将Netty IN ACTI ...

  2. netty 文件传输

    FileServer package com.zhaowb.netty.ch13_1; import io.netty.bootstrap.ServerBootstrap; import io.net ...

  3. NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?

    一:NETTY 是什么? Netty 是什么?  这个问题其实百度上一搜一堆. 这是官方话的描述:Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个 ...

  4. [Netty] - Netty入门(最简单的Netty客户端/服务器程序)

    Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是< ...

  5. NIO学习笔记,从Linux IO演化模型到Netty—— Netty零拷贝

    Netty的中零拷贝与上述零拷贝是不一样的,它并不是系统层面上的零拷贝,只是相对于ByteBuf而言的,更多的是偏向于数据操作优化这样的概念. Netty中的零拷贝: 1.CompositeByteB ...

  6. Netty实战四之传输

    流经网络的数据总是具有相同的类型:字节(网络传输——一个帮助我们抽象底层数据传输机制的概念) Netty为它所有的传输实现提供了一个通用的API,即我们可以将时间花在其他更有成效的事情上. 我们将通过 ...

  7. Netty 系列二(传输).

    一.前言 上一篇文章我们提到 Netty 的核心组件是 Channel.回调.Future.ChannelHandler.EventLoop,这篇文章主要是对 Channel (Netty传入和传出数 ...

  8. 一起来读Netty In Action之传输(三)

    当我们的应用程序需要接受比预期多很多的并发连接的时候,我们需要从阻塞传输切换到非阻塞传输上去,如果是我们的网络编程是基于jdk提供的API进行开发地的话,这种传输模式的切换几乎要我们重构整个网络传输相 ...

  9. 在dubbo的一端,看Netty处理数据包,揭网络传输原理

    如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...

  10. netty: marshalling传递对象,传输附件GzipUtils

    netty: marshalling传递对象,传输附件GzipUtils 前端与服务端传输文件时,需要双方需要进行解压缩,也就是Java序列化.可以使用java进行对象序列化,netty去传输,但ja ...

随机推荐

  1. Android报错:WindowManager$BadTokenException: Unable to add window -- window has already been added

    很久之前测试通过的代码,现在手机升级了Android7.0后一运行就崩溃,报出这样的错误,具体错误如下: Process: com.example.sho.android_anti_theft, PI ...

  2. Oracle dual表的用途

    dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录.我们可以用它来做很多事情,如下: 1.查看当前用户,可以在 SQL Plus中执行下面语句 sele ...

  3. web前端概念巩固(一)

    h5: 1.web语义化 Web语义化是指在进行HTML结构.表现.行为设计时,尽量使用语义化的标签,使程序代码简介明了,易于进行Web操作和网站SEO,方便团队协作的一种标准,以图实现一种" ...

  4. 基于51单片机IIC通信的PCF8591学习笔记

    引言 PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入.一个输出和一个串行I2C 总线接口.3 个地址引脚A0.A1 和A2 用于编程硬件地址,允许将最多8 个器件连接 ...

  5. jquery如何设置html众标签中的值

    $("img").attr("src",some_url);//jquery设置img标签中的src值 $("#user").val(&qu ...

  6. struts2 之 struts2数据校验

    1. 数据校验一般分为2类:前端的校验(js校验),后端的校验(java代码):实际开发中大部分情况下都是采用js校验.在对数据安全要求较高的情况下可能会采用后端验证. 2.  Struts2提供了后 ...

  7. FreeSWITCH 安装配置的 各种坑, 填坑

    个人安装环境: OS:CentOS6.7 64位 FreeSWITCH Ver:1.6.17 一. 编译出错 安装 之前, 最好 先安装 这几个东西(如果有, 请忽略): yasm (有nasm的话 ...

  8. 0-创建scott示例数据

    CREATE TABLE dept (  deptno INT PRIMARY KEY,  dname VARCHAR(14),  loc VARCHAR(13) );   INSERT INTO d ...

  9. stm32之USART学习

    首先,我是看着这位博主的文章受到的启发,进而加深了自己对USART的理解.下面是自己改装并实验过的程序. 原文:http://www.cnblogs.com/greatwgb/archive/2011 ...

  10. Kruskal和Prim算法求最小生成树

    Kruskal算法求最小生成树 测试数据: 5 6 0 1 5 0 2 3 1 2 4 2 4 2 2 3 1 1 4 1 输出: 2 3 1 1 4 1 2 4 2 0 2 3 思路:在保证不产生回 ...