您的位置:首页 > 理论基础 > 计算机网络

netty入门学习

2016-10-09 10:24 411 查看
本文简单介绍下netty。Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

全部代码下载:Github链接:github链接,点击惊喜;写文章不易,欢迎大家采我的文章,以及给出有用的评论,当然大家也可以关注一下我的github;多谢;

1.netty介绍:

Netty 是一个异步的,事件驱动的网络编程框架和工具,使用Netty 可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。

也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

“快速”和“简单”并不意味着会让你的最终应用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMPT,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

2.开发准备:

引入jar包:netty-all-4.0.41.Final.jar (我使用的,大家可以选择自己合适的) 下载地址见:http://netty.io/downloads.html

使用maven:

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId> <!-- Use 'netty-all' for 4.0 or above -->
<version>X.Y.Z.Q</version>
<scope>compile</scope>
</dependency>


3.Hello world工程:

下面简单介绍一个入门工程,包括服务端和客户端代码。详细见代码注释

3.1 server端的建立

package cn.wpeace.hello;
import java.net.InetAddress;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* netty服务端建立
* 1.设置线程池
* 2.设置处理器
* 3.绑定端口
* @author peace
*
*/
public class NettyServer {
public static void main(String[] args) {
int port=8081;//服务器监听端口
EventLoopGroup bossGroup=new NioEventLoopGroup();//boss线程池
EventLoopGroup worerGroup=new NioEventLoopGroup();//work线程池
try {
ServerBootstrap bootstrap=new ServerBootstrap();//服务启动器
bootstrap.group(bossGroup,worerGroup);//指定Netty的Boss线程和work线程
bootstrap.channel(NioServerSocketChannel.class);//设置服务器通道类
bootstrap.childHandler(new ChannelInitializer<NioSocketChannel>(){//设置处理器
@Override
protected void initChannel(NioSocketChannel channel) throws Exception {
// 以("\n")为结尾分割的 解码器,用于消息识别
channel.pipeline().addLast("split",new DelimiterBasedFrameDecoder(1000, Delimiters.lineDelimiter()));
channel.pipeline().addLast("decoder",new StringDecoder());//对字符串进行处理  解码器
channel.pipeline().addLast("encoder",new StringEncoder());//对字符串进行处理  编码器
channel.pipeline().addLast("hander",new FirstServerHandler());//自定义的处理器

}
});
ChannelFuture future = bootstrap.bind(port).sync();//设置绑定的端口
future.channel().closeFuture().sync();

} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
worerGroup.shutdownGracefully();
}
}
}
/**
* 自定义处理类
* @author peace
*
*/
class FirstServerHandler extends SimpleChannelInboundHandler<String>{
/**
* 消息过来后执行此方法
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(ctx.channel().remoteAddress()+":"+msg);
ctx.writeAndFlush("received your message:"+msg);
}
/**
* 通道被客户端激活时执行此方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");//通道激活
ctx.writeAndFlush( "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n");//回送进入服务系统
}

}


3.2 client端的建立

package cn.wpeace.hello;
import java.util.Scanner;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 客户端建立
* 1.设置线程池
* 2.设置处理器
* 3.连接端口
* @author peace
*
*/
public class NettyClient {
public static void main(String[] args) {
String host="127.0.0.1";//服务端IP
int port=8081;//端口
EventLoopGroup group=new NioEventLoopGroup();//线程池
try {
Bootstrap bootstrap=new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {//设置处理器
@Override
protected void initChannel(NioSocketChannel channel) throws Exception {
channel.pipeline().addLast("split",new DelimiterBasedFrameDecoder(1000, Delimiters.lineDelimiter()));
channel.pipeline().addLast("decoder",new StringDecoder());
channel.pipeline().addLast("encoder",new StringEncoder());
channel.pipeline().addLast("hander",new FirstClientHandler());//自定义客户端处理器
}
});
Channel channel = bootstrap.connect(host,port).sync().channel();
Scanner scanner=new Scanner(System.in);//读取键盘输入
while(true){
String line = scanner.nextLine();
if(line==null||"".equals(line)){
continue;
}
if("exit".equals(line)){//退出字符串
channel.close();
break;
}
channel.writeAndFlush(line+ "\r\n");//\n为了分隔识别,\r为了格式化输出
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully();
}

}
}
class FirstClientHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Server :"+msg);//读取消息

}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active");//通道激活调用
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client close");//通道退出调用
super.channelInactive(ctx);
}
}


3.3运行效果:

1.服务端:



2.客户端:



4.核心类和方法介绍

4.1 EventLoopGroup用于管理Channel连接的

bossGroup线程组:

boss线程负责接收socket的连接请求,每接收一个连接请求就产生一个Channel,并把这个channel交给ServerBootstrap初始化时指定的 ServerSocketChannelFactory来处理,boss线程则继续处理socket的连接请求。

注意:ServerBootstrap监听几个端口对应几个boss线程。

workerGroup线程组:

worker线程负责继续处理channel请求。

ServerSocketChannelFactory会从worker线程组中找出一个worker线程来继续处理这个请求。

如果是OioServerSocketChannelFactory也就是阻塞型IO时,这个channel上所有的socket消息,从开始到 channel(socket)关闭,都只由这个特定的worker来处理。

如果是NioServerSocketChannelFactory也就是非阻塞型IO时,每个worker可以服务不同的socket或者说channel,worker线程和channel不再有一一对应的关系。

worker的生命周期:对于普通IO,worker线程从连接建立后就保持。对于NIO则消息来临时从worker线程组中取出一个可用的线程,执行相应的ChannelPipeline(类似过滤器)等后,如果没有产生异常则会被回收。

4.2 Bootstrap

ServerBootstrap用于绑定端口,以及初始化设置线程组,handler等

Boostarp用于连接对应的IP和端口,以及初始化。

4.3ChannelPipeline和ChannelHandler

channerlPipeLine:

Netty中的每一个Channel,都有一个独立的ChannelPipeline,中文称为“通道水管”。只不过这个水管是双向的里面流淌着数据,数据可以通过这个“水管”流入到服务器,也可以通过这个“水管”从服务器流出。

ChannelHandler:

在ChannelPipeline中,有若干的过滤器。我们称之为“ChannelHandler”(处理器或者过滤器)。同“流入”和“流出”的概念向对应:用于处理/过滤 流入数据的ChannelHandler,称之为“ChannelInboundHandler”;用于处理/过滤 流出数据的ChannelHandler,称之为“ChannelOutboundHandler”。

类似Servlet中的过滤器,也是典型的责任链模式。需要注意,虽然数据管道中的Handler是按照顺序执行的,但不代表某一个Handler会处理任何一种由“上一个handler”发送过来的数据。某些Handler会检查传来的数据是否符合要求,如果不符合自己的处理要求,则不进行处理。

4.4一些Handler类举例

StringDecoder:实现了对接收的byte数据转换为String

(blog.wpeace.cn)

HttpRequestDecoder:实现了Http协议的数据输入格式的解析。这个类将数据编码为HttpMessage对象,并交由下一个ChannelHandler进行处理。

ByteArrayDecoder:最基础的数据流输入处理器,将所有的byte转换为ByteBuf对象(一般的实现类是:io.netty.buffer.UnpooledUnsafeDirectByteBuf)。我们进行一般的文本格式信息传输到服务器时,最好使用这个Handler将byte数组转换为ByteBuf对象。

DelimiterBasedFrameDecoder:这个数据流输入处理器,会按照外部传入的数据中给定的某个关键字符/关键字符串,重新将数据组装为新的段落并发送给下一个Handler处理器。后文中,我们将使用这个处理器进行TCP半包的问题。

还有很多直接支持标准数据格式解析的处理器,例如支持Google Protocol Buffers 数据格式解析的ProtobufDecoder和ProtobufVarint32FrameDecoder处理器。

相反的有对应成对使用的解码器:HttpResponseEncoder,ByteArrayEncoder,StringEncoder;

本文来自伊豚(blog.wpeace.cn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java netty Nio 网络编程