关于Netty的一点初步认识
最初接触
刚开始接触Netty
时,搜索相关资料及教程,就看到了关于 Netty5 的一些教程;
打开Netty官网,却没有找到关于Netty5
的影子,只感觉了有点奇怪。
在Netty
官方对应Github的releases
上,最新的更新也只是关于4.x
的版本;
后来在mvnrepository上看到了关于netty5的影子,更新时间为2015年3月,后来在github releases中找到了netty5的版本,不过只更新到netty-5.0.0.Alpha2
版本就再也没有更新过;
Netty3 与 Netty4
后来进行了一些简单的对比,总结了一些简单的区别:
- 3.0.0.CR1 ~ 3.2.10.Final
maven依赖
<!-- https://mvnrepository.com/artifact/org.jboss.netty/netty -->
<!-- 3.0.0.CR1 ~ 3.2.10.Final -->
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.10.Final</version>
</dependency>
包名以org.jboss.netty
开头;
- 3.3.0.Final ~ 3.10.6.Final
maven依赖
<!-- https://mvnrepository.com/artifact/io.netty/netty -->
<!-- 3.3.0.Final ~ 3.10.6.Final -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.10.6.Final</version>
<!--<version>3.3.0.Final</version>-->
</dependency>
包名也是以org.jboss.netty
开头,只是maven依赖的groupId名
发生一些改变;
- 4.0.0.Final ~ 4.1.35.Final
maven依赖
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<!-- 4.0.0.Final ~ 4.1.35.Final ~ 5.0.0.Alpha2 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.35.Final</version>
<!--<version>5.0.0.Alpha2</version>-->
</dependency>
包名改变为以io.netty
开头,maven依赖的artifactId名
发生一点改变;
Netty3 的一些简单实践
服务端
NettyServer.java
package morning.cat.netty3.x;
import morning.cat.netty3.x.handle.HelloHandle;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @describe: Netty3.x Server
* @author: morningcat.zhang
* @date: 2019/4/22 10:37 PM
*/
public class NettyServer {
public static void main(String[] args) {
// 服务端
ServerBootstrap bootstrap = new ServerBootstrap();
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService work = Executors.newCachedThreadPool();
// 设置 ChannelFactory 工厂
bootstrap.setFactory(new NioServerSocketChannelFactory(boss, work));
// 设置 ChannelPipelineFactory 工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
// 生成管道
ChannelPipeline channelPipeline = Channels.pipeline();
// 接收信息转换成字符串(上行)
// channelPipeline.addLast("StringDecoder",new StringDecoder());
// 回写直接写入字符串
// channelPipeline.addLast("StringEncoder",new StringEncoder());
channelPipeline.addLast("HelloHandle", new HelloHandle());
return channelPipeline;
}
});
// 绑定端口
bootstrap.bind(new InetSocketAddress(59999));
// telnet 127.0.0.1 59999
System.out.println("Netty Server start...");
}
}
HelloHandle.java
package morning.cat.netty3.x.handle;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.*;
/**
* @describe: Netty3.x Server Handle
* @author: morningcat.zhang
* @date: 2019/4/22 10:37 PM
*/
public class HelloHandle extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();
String message = new String(channelBuffer.array());
System.out.println("接收消息:" + message);
ChannelBuffer writeMsg = ChannelBuffers.copiedBuffer((" 已接收消息" + message).getBytes());
ctx.getChannel().write(writeMsg);
super.messageReceived(ctx, e);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("发生异常");
//super.exceptionCaught(ctx, e);
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("新客户端打开连接" + ctx.getName());
super.channelConnected(ctx, e);
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("关闭连接");
super.channelDisconnected(ctx, e);
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("关闭通道");
super.channelClosed(ctx, e);
}
}
客户端
package morning.cat.netty3.x.client;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @describe: Netty3.x Client
* @author: morningcat.zhang
* @date: 2019/4/22 10:37 PM
*/
public class NettyClient {
public static void main(String[] args) {
// 客户端
ClientBootstrap bootstrap = new ClientBootstrap();
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService work = Executors.newCachedThreadPool();
// 设置 ChannelFactory 工厂
bootstrap.setFactory(new NioClientSocketChannelFactory(boss, work));
// 设置管道工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
// 获取管道
ChannelPipeline channelPipeline = Channels.pipeline();
// Channel Pipeline
// 接收信息转换成string(上行)
channelPipeline.addLast("StringDecoder", new StringDecoder());
// 回写直接写入字符串
channelPipeline.addLast("StringEncoder", new StringEncoder());
channelPipeline.addLast("ClientHandle", new ClientHandle());
return channelPipeline;
}
});
// 绑定端口
ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("127.0.0.1", 59999));
System.out.println("Netty Client start...");
Channel channel = channelFuture.getChannel();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入:");
channel.write(scanner.next());
}
}
}
ClientHandle.java
package morning.cat.netty3.x.client;
import org.jboss.netty.channel.*;
/**
* @describe: 类描述信息
* @author: morningcat.zhang
* @date: 2019/4/22 10:37 PM
*/
public class ClientHandle extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("接收消息:" + e.getMessage());
super.messageReceived(ctx, e);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("发生异常");
super.exceptionCaught(ctx, e);
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("打开连接");
super.channelConnected(ctx, e);
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("关闭连接");
super.channelDisconnected(ctx, e);
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("关闭通道");
super.channelClosed(ctx, e);
}
}
Netty4 的一些简单实践
服务端
NettyServer.java
package morning.cat.netty4.x;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* @describe: Netty4.x Server
* @author: morningcat.zhang
* @date: 2019/4/23 12:13 AM
*/
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
// 用来处理I/O操作的多线程事件循环器
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 服务端
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 设置 NioSocket 工厂
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
// 设置管道工厂 ChannelHandler
serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline channelPipeline = channel.pipeline();
// 接收信息转换成string(上行)
// channelPipeline.addLast("StringDecoder", new StringDecoder());
// 回写直接写入字符串
// channelPipeline.addLast("StringEncoder", new StringEncoder());
//
//channelPipeline.addLast("EchoServerHandle", new EchoServerHandle());
//
// channelPipeline.addLast("HelloHandle", new HelloHandle());
//
channelPipeline.addLast("HelloHandle", new EchoServerHandle());
// channelPipeline.addLast("TimeServerHandler", new TimeServerHandler());
}
});
// 设置参数
serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口
// telnet 127.0.0.1 51001
// Bind and start to accept incoming connections.
ChannelFuture channelFuture = serverBootstrap.bind(51001).sync();
System.out.println("Netty4 Server start...");
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
channelFuture.channel().closeFuture().sync();
System.out.println("closeFuture");
} finally {
// 关闭资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
EchoServerHandle.java
package morning.cat.netty4.x.server.handle;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import java.nio.charset.Charset;
/**
* @describe: 类描述信息
* @author: morningcat.zhang
* @date: 2019/4/23 3:41 PM
* @see ChannelOutboundHandlerAdapter,ChannelInboundHandlerAdapter
*/
public class EchoServerHandle extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive");
super.channelInactive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead ----->");
if (msg instanceof ByteBuf) {
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println(byteBuf.toString(Charset.defaultCharset()));
}
//ByteBuf byteBuf = ByteBufUtil.writeUtf8(ByteBufAllocator.DEFAULT, "server已收到此消息\n");
//ctx.write(byteBuf);
//super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelReadComplete");
// Channel channel = ctx.channel();
// channel.writeAndFlush();
ctx.flush();
//super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("exceptionCaught");
super.exceptionCaught(ctx, cause);
}
}
客户端
package morning.cat.netty4.x.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import morning.cat.netty4.x.client.handle.ClientHandle;
import morning.cat.netty4.x.client.handle.EchoClientHandler;
import java.util.Scanner;
/**
* @describe: 类描述信息
* @author: morningcat.zhang
* @date: 2019/4/23 3:23 PM
*/
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
// 用来处理I/O操作的多线程事件循环器
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 客户端
Bootstrap clientBootstrap = new Bootstrap();
// 设置 NioSocket 工厂
clientBootstrap.group(workerGroup);
clientBootstrap.channel(NioSocketChannel.class);
// 设置管道工厂
clientBootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline channelPipeline = channel.pipeline();
channelPipeline.addLast("ClientHandle", new EchoClientHandler());
}
});
// 设置参数
clientBootstrap.option(ChannelOption.SO_BACKLOG, 128);
// 连接服务端
ChannelFuture channelFuture = clientBootstrap.connect("127.0.0.1", 51001).sync();
System.out.println("Netty4 Client start...");
//channelFuture.channel().closeFuture().sync();
// Channel channel = channelFuture.channel();
// Scanner scanner = new Scanner(System.in);
// while (true) {
// System.out.print("请输入:");
// String ss = scanner.next();
// if (ss.equals("exit")) {
// break;
// }
// channel.writeAndFlush(ss);
// }
} finally {
// 关闭资源
workerGroup.shutdownGracefully();
}
}
}
package morning.cat.netty4.x.client.handle;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
* @describe: 类描述信息
* @author: morningcat.zhang
* @date: 2019/9/24 2:34 PM
*/
public class EchoClientHandler extends ChannelInboundHandlerAdapter {
private final ByteBuf firstMessage;
/**
* Creates a client-side handler.
*/
public EchoClientHandler() {
firstMessage = Unpooled.buffer(128);
// for (int i = 0; i < firstMessage.capacity(); i++) {
// firstMessage.writeByte((byte) i);
// }
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
firstMessage.writeBytes("HelloNetty".getBytes());
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
附录
对于并发编程网netty5指南,最好结合Netty
提供的example工程对比着进行学习及实践。
对于并发编程网上的关于Netty的文章,有些还是值得慢慢学习的。