Anroid搭建一个局域网Web服务器

前言

 

  很多开发者看到这个标题表示很怪异,Android怎么可能搭建服务器呢?根本用不到呀,这个项目毫无价值。我表示很理解这一类的开发者,毕竟每个人的经验经历都是有限的。

  必须要说说我们的用处(需要用这个功能的人自然不用解释),比如在TV开发中,现在我们有一个电视盒子,上面跑着我们的一个apk,假如我们现在用微信网页或者QQ网络连接了我们的apk软件,我们需要把一个视频传到电视上播放,这个时候是不是需要我们的apk作为服务端来接受文件了?这只是一个例子,可能还有局限性,更多的用处大家自己去发挥噢。

  在写博客之前我已经做了一个Android Http Server的开源项目,我把它取名叫AndServerAndServer源代码托管在Github:https://github.com/yanzhenjie/AndServerAndServerAndroid 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官网下载HttpClientHttpCore的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());// 增加下载接口

  

这里可以注册很多个接口,我们后面的接口对象是实现了HttpCoreHttpRequestHandler接口的自定义类,比如我们上面的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服务

  

前面准备的几步都是为这一步准备参数的,把我们前面准备好的httpProcessorhttpParamshandlerRegistry都传到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);

          // 开启一个线程去处理这个请求,不阻塞当前线程。

          RequestHandleTask requestTask = new RequestHandleTask(this, httpService, serverConnection);

          requestTask.setDaemon(true);

          AndWebUtil.executeRunnable(requestTask);

     }

}

  

RequestHandleTask中的run方法中,我们只要判断HttpServerConnection是连接的,就调用HttpServicehandleRequest方法交给HttpCore去分析请求,并自动分发到我们刚才注册的login接口中。


1

2

3


while (mServerConnection.isOpen()) {

     mHttpService.handleRequest(mServerConnection, new BasicHttpContext());

}

  当HttpCore分析出来这个连接中的请求符合我们刚才注册的接口:


1

handlerRegistry.register("/login"new RequestLoginHandle());// 增加登录接口

  

它会自动调用RequestLoginHandlehande()方法,因为我们实现了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.

                RequestHandleTask requestTask = 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) {

          }

      }

   }

}

好了咯,主要代码就是这些,剩下的自己去发挥吧!

时间: 2024-10-09 12:17:54

Anroid搭建一个局域网Web服务器的相关文章

Ubuntu16.04最快捷搭建小型局域网Git服务器

导读 使用linux操作系统,不得不提Git版本管理器,这个Linus花了两周时间开发的分布式版本管理器(这就是大神,先膜了个拜...),毫无疑问,Git版本管理器与linux系统有着与生俱来的同一血缘,故而其在linux上的表现也是如鱼得水. 那么在linux上面管理文档.程序.源码等文件最好的就是Git了,而且Git是分布式,不必与中心服务器通讯即可管理本地版本.然而,对于一个协同工作的小型团队来说,仅靠本地版本管理是严重不够的,必须通过信息交互使团队的版本保持一致,方可确保团队的方向一致.

搭建一个webpack微服务器

[前言]:因为最近在vue2.0的时候用到了webpack的externals,才发现我之前都只是用webpack做一些搭建完项目后的"收尾工作"--即打包,而没有把它纳入到项目开发的"主体过程"中来,真是"物不尽其用".于是就有了我今天的这篇学习文章:利用webpack-dev-server搭建一个webpack的服务器 参考资料: webpack-dev-server的github地址:https://github.com/webpack/w

【重要】怎么自行搭建简单的web服务器

# -*- coding: utf-8 -*- #python 27 #xiaodeng #CGI模块 #怎么自行搭建简单的web服务器 #用途: #内网中,提供文件的共享服务非常有用,在cmd下启动运行服务器命令之后,其他电脑也是可以通过url访问的 #可以实现pdf.zip等压缩文件.exe.apk等软件的下载服务. ###搭建基本流程## #1.假定共享文件的目录为:/home/test,ip为#192.168.1.101 ''' 怎么查看本机IP? import socket mynam

【日记】搭建一个node本地服务器

用node搭建一个本地http服务器.首先了解htpp服务器原理 HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端.HTTP协议采用了请求/响应模型.客户端向服务器发送一个请求报文,请求报文包含请求的方法.URL.协议版本.请求头部和请求数据.服务器以一个状态行作为响应,响应的内容包括协议的版本.成功或者错误代码.服务器信息.响应头部和响应数据.下图表明了这种请求/响应模型. 以下是HTTP请求/响应的步骤: (1)客户端连接到Web服务器 一

linux系统下搭建自己的web服务器

之前在windows 2008 server上搭建了一个用于测试的web服务器,但是在打开网站的时候特别的慢,尤其是图片的加载都会失败,当时以为是路径的问题,但是在服务器上自己打开都特别慢,自己实在找不到原因,所以打算不在一棵树上面吊死,准备去linux下试试. 经常被拿来当服务器的有centos.ubuntu......考虑到自己只有ubuntu的镜像并且只是自己做一些简单的测试使用,所以选择的版本是ubuntu14.04LTS.在这个平台上搭建自己的web服务器 相比在windows下的wa

Socket 初识 用Socket建立一个简易Web服务器

摘自<Asp.Net 本质论>作者:郝冠军 //在.Net中.system.Net命名空间提供了网络编程的大多数数据据类型以及常用操作,其中常用的类型如下:/*IPAddress 类表示一个IP地址* IPEndPoint类用来表示一个IP地址和一个端口号的组合,成为网络的端点.* System.Net.Sockets命名空间中提供了基于Socked编程的数据类型.* Socket类封装了Socked的操作.* 常见的操作:* Listen:设置基于连接通信的Socket进入监听状态,并设置等

用nodejs搭建一个简单的服务器

使用nodejs搭建一个简单的服务器 nodejs优点:性能高(读写文件) 数据操作能力强 官网:www.nodejs.org 验证是否安装成功:cmd命令行中输入node -v 如果显示版本号表示安装成功 [常用命令] 切换盘符 d:进入文件夹 cd nodejs返回上一级目录 cd..清屏 cls展示目录 dir复制文件名 选中右键--复制历史操作 上箭头 执行文件 node 文件名(在文件文件夹目录中)停止命令行 ctrl+c nodejs可以使用的ECMAScript.读写文件.数据库操

深入理解Tornado——一个异步web服务器

本人的第一次翻译,转载请注明出处:http://www.cnblogs.com/yiwenshengmei/archive/2011/06/08/understanding_tornado.html原文地址:http://golubenco.org/?p=16 这篇文章的目的在于对Tornado这个异步服务器软件的底层进行一番探索.我采用自底向上的方式进行介绍,从轮巡开始,向上一直到应用层,指出我认为有趣的部分.所以,如果你有打算要阅读Tornado这个web框架的源码,又或者是你对一个异步we

node搭建一个简单的服务器

搭建一个简单的服务器 1 引入http模块 两个参数 req: request 请求 res: responese 响应 module require('mod1') node_modules 文件 require('./mode1') 发布自己的模块 去 npmjs.com 去注册一个账户 在控制台中 npm login username password email npm init npm publish cnpm install express const express = requi