**用netty写个hello world**
要成为架构师,了解一些框架内部的通信机制的必不可少的,所以最近学习了netty的相关知识,本次就先用netty写个“hello world”来体验下。
Netty或多或少应该都听说过,我这里就不用在赘述他的背景,netty的内部通讯模式有多种:
NIO io.netty.channel.socket.nio 使用java.nio.channels 包作为基础——基于选择器的方式
Epoll io.netty.channel.epoll 由 JNI 驱动的 epoll()和非阻塞 IO。这个传输支持只有在Linux 上可用的多种特性,按照作者的话来说在linux下使用这种通讯模式能获得更高的性能,能减少GC次数.将NioEventLoopGroup替换为EpollEventLoopGroup , 并且将NioServerSocketChannel.class 替换为EpollServerSocketChannel.class 即可。
OIO io.netty.channel.socket.oio 使用java.net 包作为基础——使用阻塞流(相当于BIO)
Local io.netty.channel.local 可以在VM 内部通过管道进行通信的本地传输
Embedded io.netty.channel.embedded Embedded 传输,允许使用ChannelHandler 而又不需要一个真正的基于网络的传输。在测试ChannelHandler 实现时非常有用
这里主要是用NIO的方式,NIO的原理会单独分享和实现,netty的帮助程序员封装起了NIO的使得代码编写起来会比较简单,了解一个新的东西要先从大的方向去了解,netty的核心组件:
1.channel java的channel是网络io和文件io通用,netty的channel只包含网络通讯的功能。
netty的channel并没有继承java的channel;
2、EventLoop、EventLoopGroup
3.事件和ChannelHandler
应用程序开发人员的角度来看,Netty 的主要组件是ChannelHandler,
它充当了所有处理入站和出站数据的应用程序逻辑的地方。
Netty 以适配器类的形式提供了大量默认的ChannelHandler 实现,
帮我们简化应用程序处理逻辑的开发过程。
开始:
先写客户端:
public class NettyClient {
private ChannelFuture f;
public void connect(String ip,Integer port){
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
//程序启动器
Bootstrap b =new Bootstrap();
try {
b.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
f = b.connect(ip, port).sync();/*连接到远程节点,阻塞等待直到连接完成*/
f.channel().closeFuture().sync();/*阻塞,直到channel关闭*/
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
int port =8080;
NettyClient client = new NettyClient();
client.connect("localhost",port);
}
Netty是 Reactor模型的是基于事件驱动的,所以可以看到具体业务是由handler来处理, ChannelPipeline 提供了ChannelHandler 链的容器,并定义了用于在该链上传播入站和出站事件流的API。
public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
protected NettyClientHandler() {
super();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
// System.out.println("hello , i am client");
ByteBuf buf= Unpooled.copiedBuffer("hello server",CharsetUtil.UTF_8);
ctx.writeAndFlush(buf);
}
/* @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
ByteBuf buf= (ByteBuf) msg;
System.out.println("accept msg:" + buf.toString(CharsetUtil.UTF_8));
}*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("client accept:"+byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
服务端:
public void bind(Integer port){
EventLoopGroup bossGroup=new NioEventLoopGroup();//selector[]
EventLoopGroup workGroup=new NioEventLoopGroup();
ServerBootstrap b =new ServerBootstrap();
try {
b.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerOutBandHandler());
socketChannel.pipeline().addLast(new NettyServerInBandHandler());
}
});
ChannelFuture f =b.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
Integer port =8080;
NettyServer nettyServer= new NettyServer();
nettyServer.bind(port);
}
ChannelPipeline是有入栈出站顺序的,通常把出站的放在前面,因为有执行顺序会先执行出站的读,可以做检测过滤相关操作
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("server accept:"+byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
System.out.println("读完");
ctx.writeAndFlush(Unpooled.copiedBuffer("hello client 3",CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
定义了一个出站的handler和一个入栈的
public class NettyServerOutBandHandler extends ChannelOutboundHandlerAdapter {
public NettyServerOutBandHandler() {
super();
}
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
super.connect(ctx, remoteAddress, localAddress, promise);
System.out.println("连接成功!");
}
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
super.read(ctx);
// System.out.println(ctx.read());
// ctx.writeAndFlush(Unpooled.copiedBuffer("hello client1",CharsetUtil.UTF_8));
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
super.write(ctx, msg, promise);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello client2",CharsetUtil.UTF_8));
}
}
运行结果,先启动服务端,后启动客户端