Netty实战第四章:传输
比较java自带的OIO、NIO、Netty提供的OIO、Netty提供的NIO。
OIO:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class PlainOioServer {
final int port = 8888;
public void server() throws IOException{
// 绑定端口
final ServerSocket server = new ServerSocket(this.port);
try {
while(true){
// 阻塞接受请求
final Socket socket = server.accept();
// 开启新线程处理请求。
new Thread(new Runnable(){
public void run(){
try {
InputStream input = socket.getInputStream();
OutputStream output = socket.getOutputStream();
output.write("ok".getBytes());
output.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
server.close();
}
}
}
NIO
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.util.Iterator;
import java.util.Set;
public class PlainNioServer {
private int port = 8888;
public void server() throws IOException{
final ServerSocketChannel channel = ServerSocketChannel.open();// 开启channel
ServerSocket serverSocket = channel.socket();
serverSocket.bind(new InetSocketAddress(this.port));// 将serverSocket绑定到指定端口。
Selector select = Selector.open();// 打开selector,将channel注册到selector中。
channel.register(select, SelectionKey.OP_ACCEPT); // selector注册为可接收请求。
final ByteBuffer msg = ByteBuffer.wrap("ok".getBytes());
while(true){
select.select();// 阻塞直到新的事件到达。
Set<SelectionKey> keys = select.selectedKeys();// 获取所有事件的keys。
Iterator<SelectionKey> it = keys.iterator();
while(it.hasNext()){
SelectionKey key = it.next();
if (key.isAcceptable()){
}
if (key.isWritable()){
}
}
}
}
}
Netty自带的OIO:
import java.net.InetSocketAddress;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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;
public class NettyOioServer {
private int port ;
public NettyOioServer(int port ){
this.port = port;
}
public void server(){
EventLoopGroup group = new OioEventLoopGroup();// 创建阻塞型io。
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group)
.channel(OioServerSocketChannel.class)// IO类型不同,指定socketchannel为阻塞类型。
.localAddress(new InetSocketAddress(this.port))// 将server绑定到指定端口上
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ct , Object msg){
}
@Override
public void channelReadComplete(ChannelHandlerContext ct ){
}
});
}
});
ChannelFuture future = bootstrap.bind().sync();// 应该是现有bootstrap执行bind到channelFuture上
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Netty自带的NIO:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyNioServer {
private int port ;
public NettyNioServer(int port ){
this.port = port;
}
public void server() throws InterruptedException{
EventLoopGroup group = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group)
.channel(NioServerSocketChannel.class)// 申明了IO类型
.localAddress(new InetSocketAddress(this.port))//绑定了端口号
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
// 处理客户端发来的信息
@Override
public void channelRead(ChannelHandlerContext ctx , Object msg){
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx){
}
});
}
});
// 将启动器绑定到channelFuture 上,同步阻塞绑定。
ChannelFuture future = bootstrap.bind().sync();
// 获取channel,在执行完毕后关闭,同步阻塞关闭。
future.channel().closeFuture().sync();
} finally{
group.shutdownGracefully().sync();
}
}
}
java JDK自带的OIO和NIO属于不同的编程模式,Netty通过统一的编程规范,把NIO和OIO统一为相识的编程模式。
传输API:
每个channel都会被分配一个channelPipeLine和channelConfig,channelPipeline相当于channelHandler容器,通过将channelHandler add到pipeline中,管理channelHandler,形成适配器方式的管理, channelPipeline不仅包含处理事件,还包含需要处理的入站和出站的数据。
ChannelHandler处理的常规事件:
1 , 将数据从一种格式转换为另一种格式。比如decode、encode。
2 , 提供异常的通知。比如exceptionCaught。
3 , 提供给用户事件通知消息。
4 , 当channel注册到EventLoop或者从EventLoop注销时的通知。
channelPipeLine可以动态的向Pipeline中添加channelHandler,例如当需要支持STRATTLS协议时,可以向PIpeline中添加对应的handler,也实现了拦截器模式。
channel支持多线程操作,在多线程下也是安全的。
Netty数据传输:
Netty提供几种数据传输方法,不同的数据传输方式支持的协议不同,主要的数据传输方式:
1 , NIO,基于java NIO的数据传输方式,使用selector注册的方式。
2 , epoll,由JNI提供的epoll()支持。
Netty为linux提供的一组基于JNI的epoll()方法的NIO,如果应用程序在linux中运行,性能好于java自带的NIO。
3 , local,在VM内部传输数据。
提供了在同一个JVM中运行的客户端和服务器异步通信的API,在channel启动的时候就注册了,没有网络流量的交互,不能与其他方式交换数据。
4, OIO的方式。
阻塞的方式。
5 , embedding的方式。