Anroid搭建一个局域网Web服务器
2016-06-30 08:31
531 查看
前言
很多开发者看到这个标题表示很怪异,Android怎么可能搭建服务器呢?根本用不到呀,这个项目毫无价值。我表示很理解这一类的开发者,毕竟每个人的经验经历都是有限的。必须要说说我们的用处(需要用这个功能的人自然不用解释),比如在TV开发中,现在我们有一个电视盒子,上面跑着我们的一个apk,假如我们现在用微信网页或者QQ网络连接了我们的apk软件,我们需要把一个视频传到电视上播放,这个时候是不是需要我们的apk作为服务端来接受文件了?这只是一个例子,可能还有局限性,更多的用处大家自己去发挥噢。
在写博客之前我已经做了一个
Android Http Server的开源项目,我把它取名叫
AndServer,
AndServer源代码托管在Github:https://github.com/yanzhenjie/AndServer。
AndServer是
Android Http Server的简写,顾名思义AndServer是Android端Http服务器的一个项目。
目的在于在Android可以很方便的搭建Http服务器,这几天有人问我局域网Client和Client通信的时候有时候用什么技术比较好,其实我想到的是Socket和Http,我们知道Http是基于Socket的,所以它是一个非常成熟的Socket,所以我选择了用Http来实现,今天的博客内容也是主要讲Android端如何搭建一个Http服务器。
AndServer如何引用
如果不想研究原理,只是想快速解决项目中的问题的同学,直接依赖AndServer,具体用法往下看,或者从Github上下载AndServer的Demo。这里给出AndroidStudio和Eclipse的使用方式:
Eclipse使用Jar包,如果需要依赖源码,请自行下载。
下载Jar包
AndroidStudio使用Gradle构建添加依赖(推荐)
compile ‘com.yanzhenjie:andserver:1.0.1′
Android端用什么技术实现Http服务器
ApacheHttpCore是一个优秀的Http底层框架,支持构建服务器,支持构建客户端,所以我们第一个版本选择了Apache的
HttpCore,因为Android弃用了
ApacheHttpClient相关API,代码中会有弃用的警告,不过这一点大家不要担心,下面会给出解决方案。
Android弃用了HttpClient后怎么继续使用HttpClient
Android6.0之后SDK中删除HttpClient相关的API,我看了Google的官方文档后提示我们,如果还想继续使用
HttpClient的话:
方案一:AndroidStuid主module的gradle中配置:
android { useLibrary ‘org.apache.http.legacy‘ }
如果提示编译不过的话,需要在
android-sdk-windows\platforms\android-23\optional下检查有没有以下两个文件:
optional.json
org.apache.http.legacy.jar
如果你的SDK下没有
org.apache.http.legacy.jar的话到这里下载。
方案二:如果你使用的是Eclipse
拷贝
android-sdk-windows\platforms\android-23\optional下的org.apache.http.legacy.jar到你项目的libs下就完结。
方案三:下载Apache的jar包(不推荐)
从Apache官网下载
HttpClient和
HttpCore的jar包导入到项目。地址是:http://hc.apache.org/downloads.cgi。
但是我推荐方案一和方案二,因为AndroidSDK中删除了
HttpClient的api,但是手机系统里面还是有
HttpClient的api的。方案一和二的原理最终都是引用SDK下
android-sdk-windows\platforms\android-23\optional下的
org.apache.http.legacy.jar这个jar包到项目中,是Google处理过的jar,添加了
AndroidHttpClient等适合Android使用的api,体积相对从Apache官网下载的jar小的多。
如何使用AndServer
这里先给大家看下AndServer怎么用,下一步详解如何一步步用
HttpCore实现一个简易的
HttpServer。
(一)实现AndServerRequestHandler接口,相当Servlet
我们每写一个服务端接口,就要一个对应的类来处理,这里要实现
AndServerRequestHandler接口,相当于Java继承Servet一样,我们只需要处理Request,在Response中给出响应即可:
1 2 3 4 5 6 7 | public class AndServerTestHandler implements AndServerRequestHandler { @Override public void handle(HttpRequest rq,HttpResponse rp,HttpContext ct) throws HttpException,IOException { response.setEntity( new StringEntity( "请求成功。" , "utf-8" )); } } |
(二)在AndServer上注册接口名称,并启动服务器
在启动
AndServer的时候最好放在Service中,这里给出启动的关键代码。指定服务器的端口号,并注册接口,再启动服务器:
1 2 3 4 5 6 7 8 9 10 11 12 | AndServerBuild andServerBuild = AndServerBuild.create(); andServerBuild.setPort( 4477 ); // 指定http端口号。 // 注册接口。 andServerBuild.add( "test" , new AndServerTestHandler()); // 这里还可以注册很多接口。 // 构建AndServer并启动服务器。 AndServer andServer = andServerBuild.build(); andServer.launch(); |
WebServer了。
(三)其他设备如何访问
如果是浏览器方法,和我们普通访问网站没有区别,比如访问我们上面的接口:
Android本机访问的地址:http://locahost:4477/test 局域网其他设备访问地址:http://192.168.1.116:4477/test
如果是其它Android系统的设备,推荐使用NoHttp来访问,
NoHttp是我的另一个Http客户端的项目,和AndWeb正好是相对的,一个做服务端,一个做客户端。
到这里怎么用AndServer和Android搭建服务端的教程就完了,如果想自己尝试利用HttpCore搭建一个Http服务端的话,请往下看。
AndroidCore实现一个简易的Http服务器
其实里边的东西比较复杂个人感觉如果你不想自己写一个这样的框架的,没有太大必要看完,但是我推荐大家往下看噢,我相信你会有收获的。这里讲解下关键的代码,一共有六步:
(一)ServerSocket构建服务端连接
我们知道Http是基于Socket的,那么服务端肯定是
ServerSocket了,所以我们这里也是需要一个
ServerSocket来接受客户端请求的:
1 2 3 | ServerSocket mServerSocket = new ServerSocket(); mServerSocket.setReuseAddress( true ); mServerSocket.bind( new InetSocketAddress(mPort)); // 绑定端口 |
(二)HttpProcessor增加Http协议处理器
这个就是添加Http协议拦截器,都是Http基本信息。
1 2 3 4 5 6 | // HTTP协议拦截器。 BasicHttpProcessor httpProcessor = new BasicHttpProcessor(); httpProcessor.addInterceptor( new ResponseDate()); httpProcessor.addInterceptor( new ResponseServer()); httpProcessor.addInterceptor( new ResponseContent()); httpProcessor.addInterceptor( new ResponseConnControl()); |
(三)HttpParams初始化Http基本信息
初始化Http连接的信息,比如超时时间,缓存区大小,是否使用GZIP等。
1 2 3 4 5 6 7 | // HTTP Attribute. HttpParams httpParams = new BasicHttpParams(); httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000 ) .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024 ) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false ) .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true ) .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "WebServer/1.1" ); |
(四)HttpRequestHandlerRegistry增加接口名称
这里要用HttpRequestHandlerRegistry把我们的
RequestHandler注册进来,这一步也是最重要的,就是我们的接口名称,相当于是注册Servlet到
web.xml中一样。
举个例子,假设访问严振杰的主页http://www.yanzhenjie.com,我的主页下假设有一个login的接口,那我们的地址是:
http://www.yanzhenjie.com/login,我们的
Android Web Server也要实现这样一个可以访问的地址,就要注册一个login的接口,所以这里是增加接口名称:
1 2 3 4 | // 注册Http接口。 HttpRequestHandlerRegistry handlerRegistry = new HttpRequestHandlerRegistry(); handlerRegistry.register( "/login" , new RequestLoginHandle()); // 增加登录接口 handlerRegistry.register( "/download" , new RequestTestHandle()); // 增加下载接口 |
这里可以注册很多个接口,我们后面的接口对象是实现了
HttpCore中
HttpRequestHandler接口的自定义类,比如我们上面的
RequestLoginHandle的实现是:
1 2 3 4 5 6 7 | public class RequestLoginHandle implements HttpRequestHandler { @Override public void handle(HttpRequest rq,HttpResponse rp,HttpContext c) { // 只要在这里处理HttpRequest,如果要发出响应数据,用HttpResponse } } |
(五)HttpService创建Http服务
前面准备的几步都是为这一步准备参数的,把我们前面准备好的
httpProcessor、
httpParams、
handlerRegistry都传到
HttpService,为下一步的Connection做好准备。
1 2 3 4 | // 创建HTTP服务。 HttpService httpService = new HttpService(httpProcessor, new ConnectionReuseStrategy(), new HttpResponseFactory()); httpService.setParams(httpParams); httpService.setHandlerResolver(handlerRegistry); |
(六)Socket、DefaultHttpServerConnection处理客户端请求
上面的工作都做完了,就用到我们最开始准备好的
ServerSocket来接受客户端的连接的socket了,接受到一个客户端的连接后,把刚才的httpParams和socket绑定到
HttpServerConnection中,开始处理请求,下面代码中有一个
RequestHandleTask类,这是一个单独的线程,因为每个请求都不能干涉服务器的主线程,所以这里新开一个非阻塞的线程去处理每一个请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 | while (isLoop) { if (!mServerSocket.isClosed()) { // 阻塞接受客户端。 Socket socket = mServerSocket.accept(); DefaultHttpServerConnection serverConnection = new DefaultHttpServerConnection(); // 接受到一个请求到,把请求和刚才的param绑定到connection中。 serverConnection.bind(socket,httpParams); // 开启一个线程去处理这个请求,不阻塞当前线程。 RequestHandleTaskrequestTask = new RequestHandleTask( this ,httpService,serverConnection); requestTask.setDaemon( true ); AndWebUtil.executeRunnable(requestTask); } } |
在
RequestHandleTask中的run方法中,我们只要判断
HttpServerConnection是连接的,就调用
HttpService的
handleRequest方法交给
HttpCore去分析请求,并自动分发到我们刚才注册的login接口中。
1 2 3 | while (mServerConnection.isOpen()) { mHttpService.handleRequest(mServerConnection, new BasicHttpContext()); } |
HttpCore分析出来这个连接中的请求符合我们刚才注册的接口:
1 | handlerRegistry.register( "/login" , new RequestLoginHandle()); // 增加登录接口 |
它会自动调用
RequestLoginHandle的
hande()方法,因为我们实现了
HttpRequestHandle接口。
到这里,如何利用
HttpCore搭建一个
Android Http Server就完成了。
把几个步骤合起来
有的同学可能不会把上面的代码整合起来,这里给出完整的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | try { ServerSocket mServerSocket = new ServerSocket(); mServerSocket.setReuseAddress( true ); mServerSocket.bind( new InetSocketAddress(mPort)); // HTTP协议拦截器。 BasicHttpProcessor httpProcessor = new BasicHttpProcessor(); httpProcessor.addInterceptor( new ResponseDate()); httpProcessor.addInterceptor( new ResponseServer()); httpProcessor.addInterceptor( new ResponseContent()); httpProcessor.addInterceptor( new ResponseConnControl()); // HTTP Attribute. HttpParams httpParams = new BasicHttpParams(); httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT,timeout) .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024 ) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false ) .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true ) .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "WebServer/1.1" ); // 注册Http接口。 HttpRequestHandlerRegistry handlerRegistry = new HttpRequestHandlerRegistry(); for (Map.Entry<String,AndServerRequestHandler> handlerEntry : mRequestHandlerMap.entrySet()) { handlerRegistry.register( "/" + handlerEntry.getKey(), new DefaultHttpRequestHandler(handlerEntry.getValue())); } // 创建HTTP服务。 HttpService httpService = new HttpService(httpProcessor, new DefaultConnectionReuseStrategy(), new DefaultHttpResponseFactory()); httpService.setParams(httpParams); httpService.setHandlerResolver(handlerRegistry); /** *开始接受客户端请求。 */ while (isLoop) { // 接收客户端套接字。 if (!mServerSocket.isClosed()) { Socket socket = mServerSocket.accept(); DefaultHttpServerConnection serverConnection = new DefaultHttpServerConnection(); serverConnection.bind(socket,httpParams); // Dispatch request handler. RequestHandleTaskrequestTask = new RequestHandleTask( this ,httpService,serverConnection); requestTask.setDaemon( true ); AndWebUtil.executeRunnable(requestTask); } } } catch (Exception e) { } finally { close(); } |
RequestHandleTask类的完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class RequestHandleTask extends Thread { private final HttpService mHttpService; private final HttpServerConnection mServerConnection; private DefaultAndServer mWebServerThread; public RequestHandleTask(DefaultAndServer webServerThread,HttpService httpservice,HttpServerConnection conn) { this .mWebServerThread = webServerThread; this .mHttpService = httpservice; this .mServerConnection = conn; } @Override public void run() { try { while (mWebServerThread.isLooping() && mServerConnection.isOpen()) { this .mHttpService.handleRequest( this .mServerConnection, new BasicHttpContext()); } } catch (IOException e) { } catch (HttpException e) { } finally { try { this .mServerConnection.shutdown(); } catch (IOException e) { } } } } |
相关文章推荐
- Qt Quick里的图形效果:阴影(Drop Shadow)
- 没有自动联想补齐代码的解决办法
- 指尖下的js ——多触式web前端开发之一:对于Touch的处理
- 基本分段存储管理方式
- 安卓简单开发-安卓自带几种动画效果
- 14.1 threading--多线程
- 抽象方法不能是static或native或synchroniz
- 【伸展树splay学习小记】
- 注解开发--基础
- iOS 开发中的争议(二)
- 【bzoj1588】【HNOI2002】【营业额统计】【splay】
- mysql+hibernate 一些报错
- 第三方的使用
- iOS 开发中的争议(一)
- Hourai Jeweled
- JavaScript中的匿名函数及函数的闭包
- iOS APP可执行文件的组成
- 一篇搞定RSA加密与SHA签名|与Java完全同步
- linux——深入理解linux内存分布—基础篇
- noip2009靶形数独(优化搜索顺序+位运算(只是常数优化,快一点))