您的位置:首页 > 其它

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();


到这里就完成了一个Android WebServer的搭建,我们已经可以通过浏览器或者NoHttp来访问我们的
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) {

}

 
}

}

}


好了咯,主要代码就是这些,剩下的自己去发挥吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: