netty写Echo Server & Client完整步骤教程(图文)

1.创建Maven工程

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1 父节点的pom.xml代码(root pom文件)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>org.example</groupId>
 8     <artifactId>echo_netty</artifactId>
 9     <packaging>pom</packaging>
10     <version>1.0-SNAPSHOT</version>
11     <modules>
12         <module>netty-server</module>
13         <module>netty-client</module>
14     </modules>
15     
16 </project>

1.2 子工程netty-server的pom.xml文件代码

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>echo_netty</artifactId>
 7         <groupId>org.example</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>netty-server</artifactId>
13 
14 
15 </project>

1.3 子工程netty-client的pom.xml文件代码

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>echo_netty</artifactId>
 7         <groupId>org.example</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>netty-client</artifactId>
13 
14 
15 </project>

1.4 修改父工程的pom.xml,修改后如下所示:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>org.example</groupId>
 8     <artifactId>echo_netty</artifactId>
 9     <packaging>pom</packaging>
10     <version>1.0-SNAPSHOT</version>
11     <modules>
12         <module>netty-server</module>
13         <module>netty-client</module>
14     </modules>
15 
16     <properties>
17         <echo-server.hostname>localhost</echo-server.hostname>
18         <echo-server.port>9999</echo-server.port>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>io.netty</groupId>
24             <artifactId>netty-all</artifactId>
25             <version>4.1.10.Final</version>
26             <scope>compile</scope>
27         </dependency>
28     </dependencies>
29 
30     <build>
31         <plugins>
32             <plugin>
33                 <artifactId>maven-compiler-plugin</artifactId>
34             </plugin>
35             <plugin>
36                 <artifactId>maven-failsafe-plugin</artifactId>
37             </plugin>
38             <plugin>
39                 <artifactId>maven-surefire-plugin</artifactId>
40             </plugin>
41             <plugin>
42                 <groupId>org.codehaus.mojo</groupId>
43                 <artifactId>exec-maven-plugin</artifactId>
44             </plugin>
45         </plugins>
46     </build>
47 </project>

1.5 修改netty-server的pom.xml,修改后如下所示:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>echo_netty</artifactId>
 7         <groupId>org.example</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>netty-server</artifactId>
13 
14     <build>
15         <plugins>
16             <plugin>
17                 <groupId>org.codehaus.mojo</groupId>
18                 <artifactId>exec-maven-plugin</artifactId>
19                 <executions>
20                     <execution>
21                         <id>run-server</id>
22                         <goals>
23                             <goal>java</goal>
24                         </goals>
25                     </execution>
26                 </executions>
27                 <configuration>
28                     <mainClass>com.echo.server.EchoServer</mainClass>
29                     <arguments>
30                         <argument>${echo-server.port}</argument>
31                     </arguments>
32                 </configuration>
33             </plugin>
34         </plugins>
35     </build>
36 
37 </project>

1.6 修改netty-client的pom.xml,修改后如下所示:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>echo_netty</artifactId>
 7         <groupId>org.example</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>netty-client</artifactId>
13 
14     <build>
15         <plugins>
16             <plugin>
17                 <groupId>org.codehaus.mojo</groupId>
18                 <artifactId>exec-maven-plugin</artifactId>
19                 <executions>
20                     <execution>
21                         <id>run-server</id>
22                         <goals>
23                             <goal>java</goal>
24                         </goals>
25                     </execution>
26                 </executions>
27                 <configuration>
28                     <mainClass>com.echo.client.EchoClient</mainClass>
29                     <arguments>
30                         <argument>${echo-server.hostname}</argument>
31                         <argument>${echo-server.port}</argument>
32                     </arguments>
33                 </configuration>
34             </plugin>
35         </plugins>
36     </build>
37 
38 </project>

 

 

2. 开始写netty客户端的代码

 

 

 

 

 

 

 

 

 

 

 

 到这里的时候,项目的结构应该是这个样子的,然后让我们修改一下EchoClient.java和EchoClientHandler.java文件的内容,修改后最终代码放在下面,大家请看:

2.1 EchoClient.java的最终代码

 1 package com.echo.client;
 2 
 3 import java.net.InetSocketAddress;
 4 
 5 import com.echo.client.handler.EchoClientHandler;
 6 import io.netty.bootstrap.Bootstrap;
 7 import io.netty.channel.ChannelFuture;
 8 import io.netty.channel.ChannelInitializer;
 9 import io.netty.channel.EventLoopGroup;
10 import io.netty.channel.nio.NioEventLoopGroup;
11 import io.netty.channel.socket.SocketChannel;
12 import io.netty.channel.socket.nio.NioSocketChannel;
13 
14 public class EchoClient {
15 
16     private final String host;
17     private final int port;
18 
19     public EchoClient(String host, int port) {
20         this.host = host;
21         this.port = port;
22     }
23 
24     public static void main(String[] args) throws Exception {
25         if (args.length != 2) {
26             System.err.println(
27                     "Usage: " + EchoClient.class.getSimpleName() +
28                             " <host> <port>");
29             return;
30         }
31         String host = args[0];
32         int port = Integer.parseInt(args[1]);
33         new EchoClient(host, port).start();
34     }
35 
36     public void start() throws Exception {
37         EventLoopGroup group = new NioEventLoopGroup();
38         try {
39             Bootstrap b = new Bootstrap();
40             b.group(group)
41                     .channel(NioSocketChannel.class)
42                     .remoteAddress(new InetSocketAddress(host, port))
43                     .handler(new ChannelInitializer<SocketChannel>() {
44 
45                         @Override
46                         protected void initChannel(SocketChannel ch) throws Exception {
47                             ch.pipeline().addLast(new EchoClientHandler());
48                         }
49 
50                     });
51             ChannelFuture f = b.connect().sync();
52             f.channel().closeFuture().sync();
53         } finally {
54             group.shutdownGracefully().sync();
55         }
56     }
57 
58 }

 

2.2 EchoClientHandler.java的最终代码

 1 package com.echo.client.handler;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.ChannelHandler.Sharable;
 6 import io.netty.channel.ChannelHandlerContext;
 7 import io.netty.channel.SimpleChannelInboundHandler;
 8 import io.netty.util.CharsetUtil;
 9 
10 @Sharable
11 public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
12 
13     @Override
14     public void channelActive(ChannelHandlerContext ctx) throws Exception {
15         ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
16     }
17 
18     @Override
19     protected void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
20         System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
21     }
22 
23     @Override
24     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
25         cause.printStackTrace();
26         ctx.close();
27     }
28 
29 }

到这的时候,如果有报错的话,一般是maven没有刷新导致的。

解决方法是,打开父工程的pom.xml ,然后点击idea的右侧的maven刷新按钮,如下图所示

 

 至此,EchoClient端的代码就写好了。暂时先不启动,先写好EchoServer,再一起启动。下面介绍EchoServer端的代码。

 

3. 开始写netty服务端的代码

 

 

3.2 修改EchoServer.java文件代码,修改后最终代码如下:

 1 package com.echo.server;
 2 
 3 import java.net.InetSocketAddress;
 4 
 5 import com.echo.server.handler.EchoServerHandler;
 6 import io.netty.bootstrap.ServerBootstrap;
 7 import io.netty.channel.ChannelFuture;
 8 import io.netty.channel.ChannelInitializer;
 9 import io.netty.channel.EventLoopGroup;
10 import io.netty.channel.nio.NioEventLoopGroup;
11 import io.netty.channel.socket.SocketChannel;
12 import io.netty.channel.socket.nio.NioServerSocketChannel;
13 
14 public class EchoServer {
15 
16     private final int port;
17 
18     public EchoServer(int port) {
19         this.port = port;
20     }
21 
22     public void start() throws Exception {
23         final EchoServerHandler serverHandler = new EchoServerHandler();
24         EventLoopGroup group = new NioEventLoopGroup();
25         try {
26             ServerBootstrap b = new ServerBootstrap();
27             b.group(group)
28                     .channel(NioServerSocketChannel.class)
29                     .localAddress(new InetSocketAddress(port))
30                     .childHandler(new ChannelInitializer<SocketChannel>() {
31 
32                         @Override
33                         protected void initChannel(SocketChannel ch) throws Exception {
34                             ch.pipeline().addLast(serverHandler);
35                         }
36                     });
37             // 此处绑定服务器,并等待绑定完成。对sync()方法的调用将导致当前Thread阻塞,直到绑定完成
38             ChannelFuture f = b.bind().sync();
39             // 由于调用了sync()方法,程序将会阻塞等待,直到服务器的Channel关闭
40             f.channel().closeFuture().sync();
41         } finally {
42             group.shutdownGracefully().sync();
43         }
44     }
45 
46     public static void main(String[] args) throws Exception {
47         if (args.length != 1) {
48             System.err.println(
49                     "Usage: " + EchoServer.class.getSimpleName() + " <port>"
50             );
51             return;
52         }
53         int port = Integer.parseInt(args[0]);
54         new EchoServer(port).start();
55     }
56 
57 }

 

3.3 修改EchoServerHandler.java文件代码,修改后最终代码如下:

 1 package com.echo.server.handler;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.ChannelHandler.Sharable;
 6 import io.netty.channel.ChannelFutureListener;
 7 import io.netty.channel.ChannelHandlerContext;
 8 import io.netty.channel.ChannelInboundHandlerAdapter;
 9 import io.netty.util.CharsetUtil;
10 
11 // @Sharable标示一个ChannelHandler可以被多个Channel安全共享
12 @Sharable
13 public class EchoServerHandler extends ChannelInboundHandlerAdapter {
14 
15     @Override
16     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
17         ByteBuf in = (ByteBuf) msg;
18         System.out.println(
19                 "Server received: " + in.toString(CharsetUtil.UTF_8));
20         // 将接收到的消息写给发送者,即客户端,而不冲刷出站消息
21         ctx.write(in);
22     }
23 
24     @Override
25     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
26         // 将未决消息冲刷到远程节点,并且关闭该Channel
27         ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
28                 .addListener(ChannelFutureListener.CLOSE);
29     }
30 
31     @Override
32     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
33         cause.printStackTrace();
34         ctx.close();
35     }
36 
37 }

至此,所有的代码已经写好,下一步进行运行测试

 

4.运行代码

4.1 打包代码

 

 

 

 当出现BUILD SUCCESS的时候,代表代码已经打包好了。

 

4.2 运行server端

 

 

 

 出现一直在转圈的时候,代表server端启动成功了

4.3 运行client端

 

 双击运行client端,然后稍等片刻,会发现下图已经出现了

Client received: Netty rocks!

这一行字。说明客户端和服务端通信成功。

 

 接着看一下server端打印的输出,如下图:

 

 

可以看到,server端已经输出了从客户端收到的消息!!!

 

至此,所有的演示都结束了,大家自己动手进行实践吧。

posted @ 2020-10-12 14:54  田野与天  阅读(1299)  评论(0编辑  收藏  举报