在这一节中,我们将介绍编译和运行Echo服务器和客户端所需的所有步骤。
Echo客户端/服务器的Maven工程
这本书的附录使用Echo客户端/服务器工程的配置,详细地解释了多模块Maven工程是如何组织的。这部分内容对于构建和运行该应用程序来说并不是必读的,之所以推荐阅读这部分内容,是因为它能帮助你更好地理解本书的示例以及Netty项目本身。
要构建Echo客户端和服务器,请进入到代码示例根目录下的chapter2目录执行以下命令:
mvn clean package
这将产生非常类似于代码清单2-5所示的输出(我们已经编辑忽略了几个构建过程中的非必要步骤)。
代码清单2-5 构建Echo客户端和服务器
[INFO] Scanning for projects...
[INFO] -------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] Chapter 2. Your First Netty Application - Echo App
[INFO] Chapter 2. Echo Client
[INFO] Chapter 2. Echo Server
[INFO]
[INFO] -------------------------------------------------------------------
[INFO] Building Chapter 2. Your First Netty Application - 2.0-SNAPSHOT
[INFO] -------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.6.1:clean (default-clean) @ chapter2 ---
[INFO]
[INFO] -------------------------------------------------------------------
[INFO] Building Chapter 2. Echo Client 2.0-SNAPSHOT
[INFO] -------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.6.1:clean (default-clean)
@ echo-client ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources)
@ echo-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.3:compile (default-compile)
@ echo-client ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to
\netty-in-action\chapter2\Client\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources)
@ echo-client ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory
\netty-in-action\chapter2\Client\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.3:testCompile (default-testCompile)
@ echo-client ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test)
@ echo-client ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ echo-client ---
[INFO] Building jar:
\netty-in-action\chapter2\Client\target\echo-client-2.0-SNAPSHOT.jar
[INFO]
[INFO] -------------------------------------------------------------------
[INFO] Building Chapter 2. Echo Server 2.0-SNAPSHOT
[INFO] -------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.6.1:clean (default-clean)
@ echo-server ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources)
@ echo-server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.3:compile (default-compile)
@ echo-server ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to
\netty-in-action\chapter2\Server\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources)
@ echo-server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory
\netty-in-action\chapter2\Server\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.3:testCompile (default-testCompile)
@ echo-server ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test)
@ echo-server ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ echo-server ---
[INFO] Building jar:
\netty-in-action\chapter2\Server\target\echo-server-2.0-SNAPSHOT.jar
[INFO] -------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Chapter 2. Your First Netty Application ... SUCCESS [ 0.134 s]
[INFO] Chapter 2. Echo Client .................... SUCCESS [ 1.509 s]
[INFO] Chapter 2. Echo Ser........................ SUCCESS [ 0.139 s]
[INFO] -------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------------
[INFO] Total time: 1.886 s
[INFO] Finished at: 2015-11-18T17:14:10-05:00
[INFO] Final Memory: 18M/216M
[INFO] -------------------------------------------------------------------
下面是前面的构建日志中记录的主要步骤:
clean
和compile
阶段;maven-jar-plugin
。Maven Reactor的摘要显示所有的项目都已经被成功地构建。两个子工程的目标目录的文件列表现在应该类似于代码清单2-6。
代码清单2-6 构建的构件列表
Directory of nia\chapter2\Client\target
03/16/2015 09:45 PM <DIR> classes
03/16/2015 09:45 PM 5,614 echo-client-1.0-SNAPSHOT.jar
03/16/2015 09:45 PM <DIR> generated-sources
03/16/2015 09:45 PM <DIR> maven-archiver
03/16/2015 09:45 PM <DIR> maven-status
Directory of nia\chapter2\Server/target
03/16/2015 09:45 PM <DIR> classes
03/16/2015 09:45 PM 5,629 echo-server-1.0-SNAPSHOT.jar
03/16/2015 09:45 PM <DIR> generated-sources
03/16/2015 09:45 PM <DIR> maven-archiver
03/16/2015 09:45 PM <DIR> maven-status
要运行这些应用程序组件,可以直接使用Java命令。但是在POM文件中,已经为你配置好了exec-maven-plugin
来做这个(参见附录以获取详细信息)。
并排打开两个控制台窗口,一个进到chapter2\Server目录中,另外一个进到chapter2\Client目录中。
在服务器的控制台中执行这个命令:
mvn exec:java
应该会看到类似于下面的内容:
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------------------------------------------------------
[INFO] Building Echo Server 1.0-SNAPSHOT
[INFO] ----------------------------------------------------------------------
[INFO]
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) >
validate @ echo-server >>>
[INFO]
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) <
validate @ echo-server <<<
[INFO]
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ echo-server ---
nia.chapter2.echoserver.EchoServer
started and listening for connections on /0:0:0:0:0:0:0:0:9999
服务器现在已经启动并准备好接受连接。现在在客户端的控制台中执行同样的命令:
mvn exec:java
应该会看到下面的内容:
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------------------------------------------------
[INFO] Building Echo Client 1.0-SNAPSHOT
[INFO] -------------------------------------------------------------------
[INFO]
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) >
validate @ echo-client >>>
[INFO]
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) <
validate @ echo-client <<<
[INFO]
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ echo-client ---
Client received: Netty rocks!
[INFO] -------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------------
[INFO] Total time: 2.833 s
[INFO] Finished at: 2015-03-16T22:03:54-04:00
[INFO] Final Memory: 10M/309M
[INFO] -------------------------------------------------------------------
同时在服务器的控制台中,应该会看到这个:
Server received: Netty rocks!
每次运行客户端时,在服务器的控制台中你都能看到这条日志语句。
下面是发生的事:
(1)一旦客户端建立连接,它就发送它的消息——Netty rocks!
;
(2)服务器报告接收到的消息,并将其回送给客户端;
(3)客户端报告返回的消息并退出。
你所看到的都是预期的行为,现在让我们看看故障是如何被处理的。服务器应该还在运行,所以在服务器的控制台中按下Ctrl+C来停止该进程。一旦它停止,就再次使用下面的命令启动客户端:
mvn exec:java
代码清单2-7展示了你应该会从客户端的控制台中看到的当它不能连接到服务器时的输出。
代码清单2-7 Echo客户端的异常处理
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------------------------------------------------
[INFO] Building Echo Client 1.0-SNAPSHOT
[INFO] --------------------------------------------------------------------
[INFO]
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) >
validate @ echo-client >>>
[INFO]
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) <
validate @ echo-client <<<
[INFO]
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ echo-client ---
[WARNING]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
. . .
Caused by: java.net.ConnectException: Connection refused:
no further information: localhost/127.0.0.1:9999
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl
.finishConnect(SocketChannelImpl.java:739)
at io.netty.channel.socket.nio.NioSocketChannel
.doFinishConnect(NioSocketChannel.java:208)
at io.netty.channel.nio
.AbstractNioChannel$AbstractNioUnsafe
.finishConnect(AbstractNioChannel.java:281)
at io.netty.channel.nio.NioEventLoop
.processSelectedKey(NioEventLoop.java:528)
at io.netty.channel.nio.NioEventLoop.
processSelectedKeysOptimized(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop
.processSelectedKeys(NioEventLoop.java:382)
at io.netty.channel.nio.NioEventLoop
.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2
.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory
$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
. . .
[INFO] --------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------------
[INFO] Total time: 3.801 s
[INFO] Finished at: 2015-03-16T22:11:16-04:00
[INFO] Final Memory: 10M/309M
[INFO] --------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:
exec-maven-plugin:1.2.1:java (default-cli) on project echo-client:
An exception occured while executing the Java class. null:
InvocationTargetException: Connection refused:
no further information: localhost/127.0.0.1:9999 -> [Help 1]
发生了什么?客户端试图连接服务器,其预期运行在localhost:9999
上。但是连接失败了(和预期的一样),因为服务器在这之前就已经停止了,所以在客户端导致了一个java.net.ConnectException
。这个异常触发了EchoClientHandler
的exceptionCaught()
方法,打印出了栈跟踪并关闭了Channel
(见代码清单2-3)。
在本章中,你设置好了开发环境,并且构建和运行了你的第一款Netty客户端和服务器。虽然这只是一个简单的应用程序,但是它可以伸缩到支持数千个并发连接——每秒可以比普通的基于套接字的Java应用程序处理多得多的消息。
在接下来的几章中,你将看到更多关于Netty如何简化可伸缩性和并发性的例子。我们也将更加深入地了解Netty对于关注点分离的架构原则的支持。通过提供正确的抽象来解耦业务逻辑和网络编程逻辑,Netty使得可以很容易地跟上快速演化的需求,而又不危及系统的稳定性。
在下一章中,我们将提供对Netty体系架构的概述。这将为你在后续的章节中对Netty的内部进行深入而全面的学习提供上下文。
[1] Netty的一组受限特性可以运行于JDK 1.6,但是JDK 8或者更高版本则是编译时必需的,包括运行最新版本的Maven。
[2] 包括Intellij IDEA。——译者注
[3] 也可以通过HomeBrew或者Scoop来安装Maven,更加简单方便。——译者注
[4] 这里对于所有的客户端连接来说,都会使用同一个EchoServerHandler
,因为其被标注为@Sharable
,这将在后面的章节中讲到。——译者注
[5] SimpleChannelInboundHandler
的channelRead0()
方法的相关讨论参见https://github.com/netty/netty/ wiki/New-and-noteworthy-in-5.0#channelread0–messagereceived,其中Netty5的开发工作已经关闭。——译者注
转载自 并发编程网 - ifeve.com