android端HttpServer的实现

这几天调查了一下在android设备上实现HTTP服务的功能,发现了NanoHTTPD,能通过java实现HTTP的功能。
https://github.com/NanoHttpd/nanohttpd

自己整了个小“栗子”,大家一起品尝学习一下,实现了从PC端浏览android设备上文件的功能。HTTP是在TCP/IP协议之上的应用层协议,咱们都做过JAVA的网络编程(java socket),再了解一下HTTP协议的规则,就很容易理解NanoHTTPD的实现原理。

一、几个关键的类
1、NanoHTTPD.java
(1)、在构造方法中指定服务端的端口号,并生成ServerSocket对象
(2)、在构造方法中有特别关键的一段,serve是抽象方法,由咱们在应用层重写实现。

        // creates a default handler that redirects to deprecated serve();
        this.httpHandler = new IHandler<IHTTPSession, Response>() {

            @Override
            public Response handle(IHTTPSession input) {
                return NanoHTTPD.this.serve(input);
            }
        };

		public Response handle(IHTTPSession session) {
			for (IHandler<IHTTPSession, Response> interceptor : interceptors) {
				Response response = interceptor.handle(session);
				if (response != null)
					return response;
			}
			return httpHandler.handle(session);   // 这里调用上边的serve方法
		}

(3)、在start()方法中生成一个ServerRunnable对象在子线程中运行

2、ServerRunnable.java(implements Runnable) // 用于在子线程中执行
(1)、在run()方法中,循环利用NanoHTTPD.start()中生成的ServerSocket对象来监听客户端的连接
Socket finalAccept = httpd.getMyServerSocket().accept();
这是很关键的一步,每建立一个连接就生成一个Socket对象。

(2)、利用finalAccept以及inputStream(inputStream = finalAccept.getInputStream())生成ClientHandler对象,并在子线程中执行。 也就是说每建立一个连接,就会生成一个Socket对象,然后对应建立一个子线程去处理。

3、ClientHandler.java(implements Runnable) // 用于在子线程中执行
在run方法中封装HttpSession,执行HttpSession的execute()方法

HTTPSession session = new HTTPSession(httpd, tempFileManager, this.inputStream, outputStream, this.acceptSocket.getInetAddress());
	session.execute();

4、HTTPSession.java
根据HTTP协议进行解析,获得URI,METHOD,PARAMS,HEADERS,COOKIES等
注意execute()方法中的最后一句:
r = httpd.handle(this); // r是Response对象,这里就关联到了1里面的handle() – > serve()方法

二、使用方法:
1、继承 ‘NanoHTTPD’ , 复写’serve()’
2、构造方法中指明端口号
3、调用NanoHTTPD的start方法,开启HTTP服务
4、主要的代码实现

package com.example.nanohttpd;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Map;

import org.nanohttpd.protocols.http.IHTTPSession;
import org.nanohttpd.protocols.http.NanoHTTPD;
import org.nanohttpd.protocols.http.response.Response;
import org.nanohttpd.protocols.http.response.Status;

import android.text.TextUtils;
import android.util.Log;

/**
 *
 * @author lixm
 *
 */
public class HttpServerImpl extends NanoHTTPD {

	//  http://172.22.158.31:8080/getFileList?dirPath=/sdcard
	//  http://172.22.158.31:8080/getFile?fileName=/sdcard/FaceFingerMatch_AD
	
    public static final int DEFAULT_SERVER_PORT = 8080;
    public static final String TAG = "lixm";

    private static final String REQUEST_ROOT = "/";
    private static final String REQUEST_TEST = "/test";
    private static final String REQUEST_ACTION_GET_FILE = "/getFile";
    private static final String REQUEST_ACTION_GET_FILE_LIST = "/getFileList";

    public HttpServerImpl() {
        super(DEFAULT_SERVER_PORT);
    }

    @Override
    public Response serve(IHTTPSession session) {
    	String strUri = session.getUri();
    	String method = session.getMethod().name();
        Log.d(TAG,"Response serve uri = " + strUri + ", method = " + method);

        
        if(REQUEST_ROOT.equals(strUri)) {   // 根目录
            return responseRootPage(session);
        }else if(REQUEST_TEST.equals(strUri)){    // 返回给调用端json串
        	return responseJson();
        }else if(REQUEST_ACTION_GET_FILE_LIST.equals(strUri)){    // 获取文件列表
        	Map<String,String> params = session.getParms();

        	String dirPath = params.get("dirPath");
        	if(!TextUtils.isEmpty(dirPath)){
        		return responseFileList(session,dirPath);
        	}        	
        }else if(REQUEST_ACTION_GET_FILE.equals(strUri)){ // 下载文件
        	Map<String,String> params = session.getParms();
        	// 下载的文件名称
        	String fileName = params.get("fileName");
        	
        	
        	File file = new File(fileName);
        	if(file.exists()){
        		if(file.isDirectory()){
        			return responseFileList(session,fileName);
        		}else{
        			return responseFileStream(session,fileName);
        		}
        	}        	
        }
        return response404(session);
    }

    private Response responseRootPage(IHTTPSession session) {

        StringBuilder builder = new StringBuilder();
        builder.append("<!DOCTYPE html><html><body>");
        builder.append("这是lixm的测试! \n");
        builder.append("</body></html>\n");
        //return Response.newFixedLengthResponse(Status.OK, "application/octet-stream", builder.toString());
        return Response.newFixedLengthResponse(builder.toString());
    }

    /**
     * 返回给调用端LOG日志文件
     * @param session
     * @return
     */
    private Response responseFileStream(IHTTPSession session,String filePath) {
    	Log.d("lixm", "responseFileStream() ,fileName = " + filePath);
        try {
            FileInputStream fis = new FileInputStream(filePath);
            //application/octet-stream
            return Response.newChunkedResponse(Status.OK, "application/octet-stream", fis);
        }
        catch (FileNotFoundException e) {        
            Log.d("lixm", "responseFileStream FileNotFoundException :" ,e);
            return response404(session);
        }
    }

    /**
     * 
     * @param session http请求
     * @param dirPath 文件夹路径名称
     * @return
     */
    private Response responseFileList(IHTTPSession session,String dirPath) {
    	Log.d("lixm", "responseFileList() , dirPath = " + dirPath);
    	List <String> fileList = FileUtils.getFilePaths(dirPath, false);
    	StringBuilder sb = new StringBuilder();
    	for(String filePath : fileList){
    		sb.append("<a href=" + REQUEST_ACTION_GET_FILE + "?fileName=" + filePath + ">" + filePath + "</a>" + "<br>");
    	}
    	return Response.newFixedLengthResponse(sb.toString());
    }  

    /**
     * 调用的路径出错
     * @param session
     * @param url
     * @return
     */
    private Response response404(IHTTPSession session) {
    	String url = session.getUri();
        StringBuilder builder = new StringBuilder();
        builder.append("<!DOCTYPE html><html><body>");        
        builder.append("Sorry, Can't Found "+url + " !");        
        builder.append("</body></html>\n");
        return Response.newFixedLengthResponse(builder.toString());
    }

    /**
     * 返回给调用端json字符串
     * @return
     */
    private Response responseJson(){
    	return Response.newFixedLengthResponse("调用成功");
    }
}

三、示例
1、示例实现了在PC上通过浏览器浏览android设备SD卡上所有文件的功能,能够打开和下载文件
2、在PC端浏览器输入http://ip:8080/getFileList?dirPath=/sdcard
3、示例代码:http://download.csdn.net/detail/dami_lixm/9882660(这个下载分太多了,用下面的链接下载)
https://download.csdn.net/download/dami_lixm/11341046 (这个下载分少)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值