华为为移动端接入提供了一整套的解决方案,就是AnyOffice,这套系统集成了VPN接入,应用商店,客户端设备管理等功能,是一个比较完善的平台。但是它提供的客户端SDK用起来很不方便,与其他厂商的VPN解决方案不同,华为提供的eSDK主要提供的是第7层协议封装的API,在7层上建立隧道进行HTTP协议的数据传输。比如替换安卓原生的的HttpClient和HttpURLConnection,用SvnHttpClient和SvnHttpURLConnection实现隧道内通讯。用法也和原生类的用法一致。
这样的API会产生几个很不方便的地方:
1、稍微复杂一点的项目,用的HTTP框架可能五花八门,比如OkHTTP,Retrofit,Volley等等,这些框架距离HttpClient和HttpURLConnection已经很遥远了。如果要修改框架或者让原有框架兼容华为的API是非常难做且容易出错的工作。
2、对于一些即时通讯协议,或者带有视频聊天或者直播的功能,那么框架就更加复杂了。有基于NIO,AIO的各种复杂的框架。虽然华为提供了一个API叫SvnSocket来实现JAVA原生Socket的功能,但是这个API也没有完全重写Socket的方法,比如常用的setKeepAlive()方法就没有实现,而且经过我的测试,有些在Socket类中使用没有问题SvnSocket也支持的方法在某些情况下调用也会抛异常。而且像是AIO,NIO这样的类就更没法实现了,所以局限性非常大,只适合小型的应用使用。
3、数据通讯不能使用HTTPS协议,如果有保密方面的需求就很难实现了
综上所述,虽然华为在设备管理方面做的还可以,但是提供的SDK对开发人员真的太不友好了,而且虽然安卓和IOS的SDK的版本已经更新到了RC10,但是接口文档和RC3几乎没有差别,还是用蹩脚的7层协议的API进行实现。非常不好用。
所以说如果想进行Http以外的协议通讯,就必须另辟蹊径了。
一个很简单的实现方案就是反向代理,把远程服务端的一个TCP或者UDP端口,通过SVN隧道映射到手机本地上来,比如我把远程的80端口映射到手机的8880端口,那么我在访问相关服务器的时候,只需把我原来框架的目标IP从远程IP改成127.0.0.1:8880,其他的逻辑完全不需要改变,只需要做个网关登录认证就可以了。这样其实就把华为的eSDK当成传统的VPN一样使用,大大减少开发工作量和迁移成本。
但是华为SDK没有实现相关隧道的功能,只提供了SvnHttpClient,SvnHttpURLConnection,SvnSocket,SvnWebView这样的几个7层协议的接口。
所以实现Socket隧道的方法只能我们自己来完成了,从理论上来说,使用7层的协议比如HTTP做3层TCP协议的代理是可以的,但是实现起来比较复杂。使用四层的Socket通信直接实现TCP隧道比较容易,只要做转发就可以了。
所谓转发,就是把一个套接字的输出流写入到另一个套接字的输出流,另一个套接字的输入流写入到当前套接字的输出流,没什么技术含量,也不需要关心3层以上使用的是什么协议,因为隧道代理不同于中间人代理,是无需针对协议的格式进行重写的。(中间人代理比较常见的是HTTP代理,由于HTTP协议有明确的规定,比如HEADER,BODY,Content-Length等等,所以代理软件只需把源报文收过来,稍作修改或者不改,生成新的报文和连接发送出去。隧道代理比较常见的是HTTPs代理和Socks5代理,由于HTTPS协议中间人无法读取里面的内容,也不能修改内容,所以只能做无脑转发)。使用隧道代理之后,无论是HTTP,HTTPS,FTP,SFTP,SSH或者即时通讯协议,流媒体协议等就都可以通过建立好的TCP隧道进行传输,完全不用担心协议格式的问题和API接口实现的问题。
使用JAVA大体的实现思路是这样的,首先使用系统原生ServerSocket监听一个本地端口,然后让应用程序将目标地址设为这个端口。然后使用ServerSocket.accept()会接收到一个Socket对象,也就是后端应用程序发来的请求。然后我们使用华为提供的API SvnSocket新建一个连