Netty是一个NIO的客户端服务器框架,它使我们可以快速而简单地开发网络应用程序,比如协议服务器和客户端。它大大简化了网络编程,比如TCP和UDP socket服务器。
“快速而简单”并不意味着开发出来的应用可维护性或性能不好。Netty已经实现了大量的协议,比如FTP,SMTP,HTTP,以及各种基于二进制和文本的传统协议。可以说Netty已经找到了一种方法来实现简单的开发,高性能,稳定性,灵活性而不需要做妥协。
Netty的结构大体如下图这样:
就设计而言,Netty给不同的传输类型,不管是阻塞的还是非阻塞的,提供了统一的接口。它基于一个灵活的和可扩展的事件模型,这使得处理不同逻辑的部分可以有效的隔离开来。它具有高度可定制的线程模型 - 单线程,一个或多个线程池,比如SEDA。它还提供无连接的datagram socket支持。
如Netty这般,功能如此强大,性能如此优良的网络库,不用在Android上真是可惜了。这里我们就尝试将Netty用在Android上。
下载Netty
首先是下载Netty。Netty的官网地址,我们可以在这里找到下载Netty的地址,当然还有许许多多的文档。这里使用了当前4.1.x最新版的Netty 4.1.4,下载地址:
|
|
解压之后,为了省事,直接将netty-4.1.4.Final/jar/all-in-one/下的netty-all-4.1.4.Final.jar拷贝进了工程下app module的libs目录下。
Netty的简单使用
不出意外,直接通过编译。接着我们就参考netty/example/src/main/java/io/netty/example/http/snoop
中client部分的代码,将Netty用起来,这主要有如下几个类:
这个class提供给外部调用的接口。使用者可以传入URL,将借由这个类,通过Netty来访问网络并获取响应。然后来看HttpClientInitializer:
这个class负责对Channel的Pipeline进行初始化,这其中最关键的是HttpClientHandler:
我们正是通过实现HttpClientHandler,而获取到Netty返回给我们的响应的。
在我们的Android应用代码中调用HttpClient
来通过Netty从网络获取响应:
当然不能忘记了在AndroidManifest.xml中添加对INTERNET权限的请求:
做完了所有这些之后,Netty基本上就可以跑起来了。不过意外还是发生了:
有一个class com.jcraft.jzlib.Inflater
找不到。这还需要添加对jzlib的依赖:
至此顺利地将Netty跑起来:
Netty的裁剪
Netty很强大,all-in-one jar用起来很方便,这很不错。但all-in-one jar有点大,其中包含的一些诸如对memcache,redis,stomp,sctp和udt等的支持,我们在移动端并不会用掉。因而需要对它做一点裁剪。
既然不能用all-in-one包,那就把需要的几个jar文件单独copy进我们的工程好了。对于android而言,目测netty-4.1.4.Final/jar/下我们需要拷贝的jar文件主要有下面这些:
用这些文件来替换之前的netty-all-4.1.4.Final.jar。遇到了编译错误:
看来是少了一些东西了,ByteBufHolder
。那就把netty-buffer-4.1.4.Final.jar
也加进工程里。再次编译,继续出错,这是在产生APK时遇到了麻烦:
总是报Duplicate files copied in APK META-INF/INDEX.LIST
的错误。这主要是因为这些jar文件里,不同的jar文件中的META-INF/INDEX.LIST
包含了相同的内容所致。这需要在build.gradle
中的android元素里添加如下的配置:
再次编译,这次则是包Duplicate files copied in APK META-INF/io.netty.versions.properties
。这证明了前面的方法是行之有效的,于是把META-INF/io.netty.versions.properties
也加进packagingOptions
的exclude列表:
再次编译,编译通过。但是在运行的时候遇到了一点小麻烦:
提示找不到class io.netty.resolver.DefaultAddressResolverGroup,看来我们的jar文件是加少了,把netty-resolver-4.1.4.Final.jar
也加进来。终于,我们前面编写的HttpClient能够正常地跑起来了。经过一番裁剪,Netty的大小大概从3.4MB减小到2.9MB。
总结一下,若不用体型巨大的netty-all
jar文件,则我们需要导入如下的这些jar文件以编译和运行Netty:
TODO
Netty的诸多抽象,比如Bootstrap,Channel,EventLoopGroup,Handler,codec,Buffer等诸多高级特性,以及它的NIO接口,这里都没有涉及,线程模型也没有仔细厘清。这里只是最最简单的一个使用范例,要把Netty很好地应用在实际的项目中,还需要对Netty本身更深入的研究。
同时,对Netty的裁剪可能也过于粗糙,或许还有更多的东西可以裁剪掉,以减小最终的APP的大小。
要使用Netty来支持HTTP/2也还需要做更多的事情。
但窥探到Netty的灵活强大,还是让我们对这个库充满期待。