说明
避免走弯路,查找各种资料,本文提供完整的NettyServer及NettyClient的完整实现,及启动,方便其他初学者参考,不对代码本身做解说。
NettyServer
新建一个maven空白项目,项目名NettyServer
根pom.xml文件中加入netty依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.44.Final</version>
</dependency>
</dependencies>
创建EchoServerHandler,具体实现
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.util.CharsetUtil;
/**
*
*/
//标示一个ChannelHandler可以被多个channel安全的共享
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in =(ByteBuf)msg;
//将消息记录到控制台
System.out.println("Server received:" + in.toString(CharsetUtil.UTF_8));
//将接受到的消息写给发送者,而不冲刷出站消息
ctx.write(in);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//将未决消息冲刷到远程节点,并且关闭改Channel
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//打印异常栈信息
cause.printStackTrace();
//关闭该Channel
ctx.close();
}
}
创建启动引导类
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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;
import java.net.InetSocketAddress;
/**
*
*/
public class EchoServer {
private final int port;
public EchoServer(int port){
this.port = port;
}
public static void main(String[] args) throws Exception {
if (args.length != 1){
System.err.println("Usage:" + EchoServer.class.getSimpleName() + "<port>");
}
int port = Integer.parseInt(args[0]);
System.out.println(port);
new EchoServer(port).start();
}
public void start() throws Exception{
final EchoServerHandler serverHandler = new EchoServerHandler();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
//添加一个EchoServerHandler到子Channel的ChannelPipeline
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(serverHandler);
}
});
//异步的绑定服务器,调用sync()方法阻塞等待直到绑定完成
ChannelFuture channelFuture = bootstrap.bind().sync();
//获取Channel的CloseFuture,并且阻塞当前线程知道它完成
channelFuture.channel().closeFuture().sync();
}finally {
//关闭EventLoopGroup,释放所有的资源
group.shutdownGracefully().sync();
}
}
}
项目配置
pom.xml文件加入maven插件
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- main方法的入口类及参数 -->
<mainClass>EchoServer</mainClass>
<arguments>
<argument>8080</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
至此,NettyServer项目已经创建完成,接下来创建NettyClient客户端
NettyClient
创建一个空白maven项目,项目名NettyClient
根pom.xml文件中加入netty依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.44.Final</version>
</dependency>
</dependencies>
EchoClientHandler
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
/**
* Created on 2020/1/16.
*/
//标记改类的实例可以被多个Channel共享
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
//当被通知Channel是活跃的时候,发送一条消息
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
}
//记录已接受消息的转储
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println("Client received:" + byteBuf.toString(CharsetUtil.UTF_8));
}
//在发生异常时,记录错误并关闭Channel
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
EchoClient
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
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.NioSocketChannel;
import java.net.InetSocketAddress;
/**
* Created by lunfu.chen on 2020/1/16.
*/
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public static void main(String[] args) throws Exception {
System.out.println(">>>>>>>args:"+args[0]+","+args[1]);
if (args.length != 2) {
System.err.println("Usage:" + EchoClient.class.getSimpleName() + "<host> <port>");
return;
}
String host = args[0];
int port = Integer.parseInt(args[1]);
new EchoClient(host, port).start();
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new EchoClientHandler());
}
});
//连接到远程节点,阻塞等待知道连接完成
ChannelFuture future = b.connect().sync();
//阻塞,知道Channel关闭
future.channel().closeFuture().sync();
} finally {
//关闭线程池并且释放所有的资源
group.shutdownGracefully().sync();
}
}
}
pom.xml文件中加入manve插件
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 此处为启动类的入口及参数 -->
<mainClass>EchoClient</mainClass>
<arguments>
<argument>localhost</argument>
<argument>8080</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
打包启动项目
编译和启动项目我提供有两种方式,本质是一样。
使用idea
本人使用的编译器是idea,因此在两个项目的Terminal窗口中输入命令
首先在NettyServer项目中操作,
mvn clean package
然后会有输出
D:\workspace_lean\netty\nettyserver>mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building nettyserver 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ nettyserver ---
[INFO] Deleting D:\workspace_lean\netty\nettyserver\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ nettyserver ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ nettyserver ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
[INFO] Compiling 2 source files to D:\workspace_lean\netty\nettyserver\target\classes
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServerHandler.java:[9,7] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServerHandler.java:[9,44] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServerHandler.java:[15,24] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServerHandler.java:[17,28] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServerHandler.java:[29,21] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServer.java:[37,27] 编码GBK的不可映射字符
[WARNING] /D:/workspace_lean/netty/nettyserver/src/main/java/EchoServer.java:[49,37] 编码GBK的不可映射字符
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ nettyserver ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\workspace_lean\netty\nettyserver\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ nettyserver ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ nettyserver ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ nettyserver ---
[INFO] Building jar: D:\workspace_lean\netty\nettyserver\target\nettyserver-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.099 s
[INFO] Finished at: 2020-01-18T10:26:24+08:00
[INFO] Final Memory: 18M/215M
[INFO] ------------------------------------------------------------------------
编译打包成功,然后在Terminal窗口中输入启动命令
mvn exec:java
随即控制台输出响应信息
D:\workspace_lean\netty\nettyserver>mvn exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building nettyserver 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ nettyserver ---
8080
接着在NettyClient项目中执行上面两个相同的命令,最后在NettyServe项目控制台会输出
Server received:Netty rocks!
在NettyClient项目控制台会输出,并且NettyClient项目随即关闭
D:\workspace_lean\netty\nettyclient>mvn exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building nettyclient 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ nettyclient ---
>>>>>>>args:localhost,8080
Client received:Netty rocks!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.536 s
[INFO] Finished at: 2020-01-18T10:32:07+08:00
[INFO] Final Memory: 8M/190M
[INFO] -------------------------------
到此,idea实现Netty Echo应用程序已实现完毕,接着介绍使用windows系统命令窗口编译和启动这一功能。
使用CMD命令窗口
打开命令窗口,进入各自的项目文件处,eg
image.png
项目路径为
image.png
进入项目位置后,依次执行mvn clean package和mvn exec:java
image.png image.png到此步,NettyServer已经启动成功,同样的方式启动NettyClient,
并且可以使用命令窗口启动多个client客户端
可以使用Ctrl+C关闭客户端,或者简单粗暴直接关闭idea或者命令窗口,使用命令关闭窗口方式示列
image.png
第一款Netty应用程序实现及启动介绍完毕!
网友评论