×
广告

基于AndroidAsync框架搭建android http server

96
hjm1fb
2017.09.16 17:46* 字数 427

使用的框架是AndroidAsync
项目地址:https://github.com/koush/AndroidAsync/tree/master/AndroidAsync/src/com/koushikdutta/async
参考的文章是:
http://programminglife.io/android-http-server-with-androidasync/
https://github.com/reneweb/AndroidAsyncSocketExamples
WifiTransfer

项目中的代码如下:

package com.duotin.car.widget.wifiTransfer;

import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;


import com.duotin.car.BaseApplication;
import com.duotin.car.R;
import com.duotin.car.constant.Constants;
import com.duotin.car.scan.AlbumManager;
import com.duotin.car.scan.ResultFile;
import com.duotin.car.scan.ResultFolder;
import com.duotin.car.util.FileUtils;
import com.duotin.car.util.Log;
import com.duotin.car.util.Tool;
import com.duotin.lib.api2.Resource;
import com.duotin.lib.api2.model.Track;
import com.duotin.lib.util.AsyncTask;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.AsyncServerSocket;
import com.koushikdutta.async.AsyncSocket;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.async.http.AsyncHttpClient;
import com.koushikdutta.async.http.AsyncHttpRequest;
import com.koushikdutta.async.http.AsyncHttpResponse;
import com.koushikdutta.async.http.body.MultipartFormDataBody;
import com.koushikdutta.async.http.body.Part;
import com.koushikdutta.async.http.callback.HttpConnectCallback;
import com.koushikdutta.async.http.server.AsyncHttpServer;
import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
import com.koushikdutta.async.http.server.AsyncHttpServerRequestImpl;
import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
import com.koushikdutta.async.http.server.HttpServerRequestCallback;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * * Created by hongjunmin on 15/8/26
 *
 * @author hongjunmin
 */
public class WifiTransferServerHolder {
    private static final String TEXT_CONTENT_TYPE = "text/html;charset=utf-8";
    private static final String CSS_CONTENT_TYPE = "text/css;charset=utf-8";
    private static final String BINARY_CONTENT_TYPE = "application/octet-stream";
    private static final String JS_CONTENT_TYPE = "application/javascript";
    private static final String PNG_CONTENT_TYPE = "application/x-png";
    private static final String WOFF_CONTENT_TYPE = "application/x-font-woff";
    private static final String TTF_CONTENT_TYPE = "application/x-font-truetype";
    private static final String SVG_CONTENT_TYPE = "image/svg+xml";
    private static final String EOT_CONTENT_TYPE = "image/vnd.ms-fontobject";
    private static final String MP3_CONTENT_TYPE = "audio/mp3";
    private static final String MP4_CONTENT_TYPE = "video/mpeg4";
    public static final int AUDIO_FILE_DURATION_THRESHOLD_IN_SECOND = 600;
    public static final String MY_IMPORTED_AUDIO = "导入的音频";
    public static final String MY_IMPORTED_MUSIC = "导入的音乐";

    private static final String TAG = "WifiTransferServerHolder";
    private static final int DEFAULT_SOCKET_PORT = 34510;
    private AsyncHttpServer mHttpServer;
    private String defaultDirectory;
    private WifiTransferAdapter mWifiTransferAdapter;
    private AsyncServer mAsyncServer = AsyncServer.getDefault();


    private static final int BufferSize = 8190;

    public WifiTransferServerHolder(WifiTransferAdapter wifiTransferAdapter) {
        mWifiTransferAdapter = wifiTransferAdapter;
    }

    public void setUp() {
        mHttpServer = new AsyncHttpServer();
        AsyncServerSocket asyncServerSocket = mHttpServer.listen(mAsyncServer, DEFAULT_SOCKET_PORT);
        mHttpServer.post("/upload", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
                final MultipartFormDataBody body = (MultipartFormDataBody) request.getBody();
                final FileUploadHolder fileUploadHolder = new FileUploadHolder();
                body.setMultipartCallback(new MultipartFormDataBody.MultipartCallback() {
                    @Override
                    public void onPart(final Part part) {
                        if (part.isFile()) {
                            body.setDataCallback(new DataCallback() {
                                @Override
                                public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                                    if (fileUploadHolder.getFileOutPutStream() != null)
                                    //已经开始传输文件
                                    {
                                        try {
                                            fileUploadHolder.getFileOutPutStream().write(bb.getAllByteArray());
                                            mWifiTransferAdapter.onRecievingFile();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                        bb.recycle();
                                    }
                                }
                            });
                        } else {
                            if (body.getDataCallback() == null) {
                                body.setDataCallback(new DataCallback() {
                                    @Override
                                    public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                                        String fileName = getFileNameFromHttpByteBufferList(bb);
                                        //还没设置文件名
                                        if (TextUtils.isEmpty(fileUploadHolder.getFileName()) && !TextUtils.isEmpty(fileName)) {
                                            generateReceivedFileAndFileStream(fileUploadHolder, fileName);
                                            mWifiTransferAdapter.onRecievingFile();
                                        }
                                    }
                                });
                            }
                        }
                        if (!TextUtils.isEmpty(part.getFilename())) {
                            if (!Track.isProgramFileName(part.getFilename())) {
                                mWifiTransferAdapter.formateNotsupported(part.getFilename());
                            }
                        }
                    }
                });
                request.setEndCallback(new CompletedCallback() {
                    @Override
                    public void onCompleted(Exception ex) {
                        response.send(new JSONObject());
                        if (fileUploadHolder.getFileOutPutStream() != null) {
                            try {
                                fileUploadHolder.getFileOutPutStream().close();
                                if (fileUploadHolder.getRecievedFile() != null && fileUploadHolder.getRecievedFile().exists()) {
                                    String filePath = fileUploadHolder.getRecievedFile().getPath();
                                    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                                    try {
                                        retriever.setDataSource(filePath);
                                    } catch (Exception e) {
                                        try {
                                            FileInputStream fI = new FileInputStream(filePath);
                                            FileDescriptor fd = fI.getFD();
                                            retriever.setDataSource(fd);
                                        } catch (Exception e1) {
                                            e1.printStackTrace();
                                        }
                                    } finally {
                                        mWifiTransferAdapter.fileReceived(fileUploadHolder.getFileName());
                                        locateProgramAndReadyToSync(retriever, fileUploadHolder.getFileName());
                                    }
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
        });
        mHttpServer.get("/wf_images/.*", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
                sendResources(request, response);
            }
        });
        mHttpServer.get("/wf_resources/.*", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
                sendResources(request, response);
            }
        });
        mHttpServer.get("/wf_files/.*", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
                sendResources(request, response);
            }
        });
        mHttpServer.get("/list", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {

                Log.d(TAG, request.getPath());
                Map<String, String> headMap = new HashMap<>();
                headMap.put("Expires:", "-1");
                headMap.put("Cache-Control:", "no-cache");
                headMap.put("Pragma:", "no-cache");
                printHead(response, TEXT_CONTENT_TYPE, headMap);
                response.send(getProgramFileNames());
            }
        });

        mHttpServer.get("/", new HttpServerRequestCallback() {
            @Override
            public void onRequest(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
                Log.d(TAG, request.getPath());
                try {
                    response.send(Resource.assetGet(BaseApplication.appContext, "wifiImport.html"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        mHttpServer.get("/temp/.*?", new HttpServerRequestCallback() {
            @Override
            public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                Log.d(TAG, request.getPath());
                Map<String, String> headMap = new HashMap<>();
                headMap.put("Expires:", "-1");
                headMap.put("Cache-Control:", "no-cache");
                headMap.put("Pragma:", "no-cache");
                headMap.put("Connection:", "keep-alive");
                printHead(response, TEXT_CONTENT_TYPE, headMap);
                try {
                    String statusLine = ((AsyncHttpServerRequestImpl) (request)).getStatusLine();
                    String[] parts = statusLine.split(" ");
                    String fullPath = parts[1];
                    fullPath = fullPath.replace("%20", " ");
                    String resourceName = fullPath.substring(fullPath.lastIndexOf("/") + 1);
                    if (resourceName.endsWith("?")) {
                        resourceName = resourceName.substring(0, resourceName.length() - 1);
                    }
                    if (!TextUtils.isEmpty(getContentTypeByResourceName(resourceName))) {
                        response.setContentType(getContentTypeByResourceName(resourceName));
                    }
                    String path = request.getMatcher().replaceAll("");
                    String storagePath = "/storage/emulated/0/";
                    File file = new File(storagePath, path);
                    FileInputStream ex = new FileInputStream(file);
                    response.sendStream(ex, ex.available());
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
            }
        });
        mHttpServer.setErrorCallback(new CompletedCallback() {
            @Override
            public void onCompleted(Exception ex) {
                Log.dMultiString("mHttpServer ErrorCallback onCompleted");
            }
        });
        if (asyncServerSocket != null) {
            mWifiTransferAdapter.setIpString(asyncServerSocket.getLocalPort());
        } else {
            mWifiTransferAdapter.setIpString(0);
        }

    }

    private void generateReceivedFileAndFileStream(FileUploadHolder fileUploadHolder, String fileName) {
        //取到文件名,生成目标文件和路径
        fileUploadHolder.setFileName(fileName);
        File exStorage = Environment.getExternalStorageDirectory();
        defaultDirectory = BaseApplication.getWifiMusicImportPath();
        if (TextUtils.isEmpty(defaultDirectory)) {
            mWifiTransferAdapter.showToast(R.string.no_external_cannot_import);
            return;
        }
        StringBuilder dir = new StringBuilder();
        dir.append(defaultDirectory);
        if (!dir.toString().contains(exStorage.getPath()))
            dir.insert(0, exStorage.getPath());
        File dirFile;
        dirFile = new File(dir.toString()); // convert spaces appropriately
        if (!dirFile.exists() || !dirFile.isDirectory()) // catch issues in the directory path
        {
            dir.replace(0, dir.length(), defaultDirectory); // replace it with defaultDirectory if invalid
            dirFile = new File(dir.toString());
        }
        File recievedFile = new File(dirFile, fileUploadHolder.getFileName());
        fileUploadHolder.setRecievedFile(recievedFile);
        BufferedOutputStream fs = null;
        try {
            fs = new BufferedOutputStream(new FileOutputStream(recievedFile));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        fileUploadHolder.setFileOutPutStream(fs);
    }

    private String getProgramFileNames() {
        List<File> importedProgramFiles = new ArrayList<>();
        importedProgramFiles.addAll(getFilesSortedByLastModified(BaseApplication.getWifiAudioImportPath()));
        importedProgramFiles.addAll(getFilesSortedByLastModified(BaseApplication.getWifiMusicImportPath()));
        JSONArray jsonArray = new JSONArray();
        for (File file : importedProgramFiles) {
            JSONObject jsonObject = new JSONObject();
            try {
                jsonObject.put("path", file.getAbsolutePath().toString());
                jsonObject.put("name", file.getName());
                jsonObject.put("size", file.length());
                jsonArray.put(jsonObject);
            } catch (Exception e) {

            }
        }
        return jsonArray.toString();
    }

    private List<File> getFilesSortedByLastModified(String path) {
        List<File> importedAudioFiles = new ArrayList<>();
        File importedAudioFolder = new File(path);
        if (importedAudioFolder.exists()) {
            File[] importedAudioArray = importedAudioFolder.listFiles();
            if (!Tool.isEmpty(importedAudioArray)) {
                importedAudioFiles = Arrays.asList(importedAudioArray);
                Collections.sort(importedAudioFiles,
                        new Comparator<File>() {
                            @Override
                            public int compare(File o1,
                                               File o2) {
                                return (int) (o1.lastModified() - o2.lastModified());
                            }
                        });
            }

        }
        return importedAudioFiles;
    }

    private void sendResources(final AsyncHttpServerRequest request, final AsyncHttpServerResponse response) {
        try {
            String statusLine = ((AsyncHttpServerRequestImpl) (request)).getStatusLine();
            String[] parts = statusLine.split(" ");
            String fullPath = parts[1];
            fullPath = fullPath.replace("%20", " ");
            String resourceName = fullPath.substring(fullPath.lastIndexOf("/") + 1);

            if (resourceName.endsWith("?")) {
                resourceName = resourceName.substring(0, resourceName.length() - 1);
            }
            if (!TextUtils.isEmpty(getContentTypeByResourceName(resourceName))) {
                response.setContentType(getContentTypeByResourceName(resourceName));
            }
            BufferedInputStream bInputStream = new BufferedInputStream(BaseApplication.appContext.getAssets().open(resourceName));
            response.sendStream(bInputStream, bInputStream.available());
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
    }

    private String getContentTypeByResourceName(String resourceName) {
        if (resourceName.endsWith(".css")) {
            return CSS_CONTENT_TYPE;
        } else if (resourceName.endsWith(".js")) {
            return JS_CONTENT_TYPE;
        } else if (resourceName.endsWith(".swf")) {
            return BINARY_CONTENT_TYPE;
        } else if (resourceName.endsWith(".png")) {
            return PNG_CONTENT_TYPE;
        } else if (resourceName.endsWith(".woff")) {
            return WOFF_CONTENT_TYPE;
        } else if (resourceName.endsWith(".ttf")) {
            return TTF_CONTENT_TYPE;
        } else if (resourceName.endsWith(".svg")) {
            return SVG_CONTENT_TYPE;
        } else if (resourceName.endsWith(".eot")) {
            return EOT_CONTENT_TYPE;
        } else if (resourceName.endsWith(".mp3")) {
            return MP3_CONTENT_TYPE;
        } else if (resourceName.endsWith(".mp4")) {
            return MP4_CONTENT_TYPE;
        }
        return "";
    }

    private void locateProgramAndReadyToSync(MediaMetadataRetriever retriever, String fileName) {
        String folderName = BaseApplication.getWifiMusicImportPath();
        String albumName = MY_IMPORTED_MUSIC;
        String duration = "0";
        Constants.TrackType trackType = Constants.TrackType.LOCAL;
        int albumId = MY_IMPORTED_MUSIC_ALBUM_ID;
        Log.dMultiString("synchronized (SingleSocketConnection.class) { 903");
        try {
            duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
            long durationInmillisec = Long.parseLong(duration);
            long durationInsec = durationInmillisec / 1000;
            if (durationInsec > AUDIO_FILE_DURATION_THRESHOLD_IN_SECOND) {
                FileUtils.moveFile(BaseApplication.getWifiMusicImportPath(), fileName, BaseApplication.getWifiAudioImportPath());
                folderName = BaseApplication.getWifiAudioImportPath();
                albumName = MY_IMPORTED_AUDIO;
                trackType = Constants.TrackType.LOCAL;
                albumId = MY_IMPORTED_AUDIO_ALBUM_ID;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readtToSync(folderName, fileName, duration, albumName, trackType, albumId);
        }
    }

    private void readtToSync(String folderName, String fileName, String duration, String albumName, Constants.TrackType trackType, int albumId) {
        if (TextUtils.isEmpty(folderName) || TextUtils.isEmpty(fileName) || TextUtils.isEmpty(albumName))
            return;
        File folder = new File(folderName);
        Map<String, String> fileNamesAndDurations = new HashMap<>();
        fileNamesAndDurations.put(fileName, duration);
        AutoAddResultFoler autoAddResultFoler = new AutoAddResultFoler(folder, folderName, fileNamesAndDurations, albumName, trackType, albumId);
        new ImportProgramesAsynTask().execute(autoAddResultFoler);
    }

    public void stop() {
        mHttpServer.stop();
        mAsyncServer.stop();
    }

    static class ImportProgramesAsynTask extends AsyncTask<ResultFolder, String, String> {

        @Override
        protected String doInBackground(ResultFolder... params) {
            ResultFolder resultFolder = params[0];
            if (resultFolder != null)
                AlbumManager.storeFolder(resultFolder);
            return null;
        }
    }

    class AutoAddResultFoler extends ResultFolder {

        public AutoAddResultFoler(File folderFile, String folderName, Map<String, String> fileNamesAndDurations, String albumName, Constants.TrackType trackType, int albumId) {
            super(folderFile);
            if (folderFile.exists() && !Tool.isEmpty(fileNamesAndDurations)) {
                setId(albumId);
                setSource(Constants.TrackSource.LOCAL_WIFI_IMPORT);
                setTrackType(trackType);
                setAlbumName(albumName);
                for (Map.Entry<String, String> entry : fileNamesAndDurations.entrySet()) {
                    File recievedFile = new File(folderName + entry.getKey());
                    if (recievedFile.exists()) {
                        ResultFile resultFile = new ResultFile(recievedFile);
                        resultFile.setToAdd(true);
                        resultFile.setSource(Constants.TrackSource.LOCAL_WIFI_IMPORT);
                        resultFile.setDuration(com.duotin.lib.api2.util.StringUtils.formatTime(entry.getValue()));
                        resultFile.setStatus(Constants.TrackState.DOWNLOAD_SUCCESSFUL);
                        addResultFile(resultFile);
                    }
                }
            }
        }

    }


    class FileUploadHolder {
        private String fileName;

        public File getRecievedFile() {
            return recievedFile;
        }

        public void setRecievedFile(File recievedFile) {
            this.recievedFile = recievedFile;
        }

        private File recievedFile;

        public BufferedOutputStream getFileOutPutStream() {
            return fileOutPutStream;
        }

        public void setFileOutPutStream(BufferedOutputStream fileOutPutStream) {
            this.fileOutPutStream = fileOutPutStream;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void reset() {
            fileName = null;
            fileOutPutStream = null;
        }

        private BufferedOutputStream fileOutPutStream;
    }

    private String getFileNameFromHttpByteBufferList(ByteBufferList bb) {
        String s = bb.readString();
        Log.dMultiString(s);
        if (Track.isProgramFileName(s)) {
            return s;
        } else {
            if (s.length() > 2) {
                s = s.substring(0, s.length() - 2);
                if (Track.isProgramFileName(s)) {
                    return s;
                }
            }
        }
        return null;
    }

    private void printHead(AsyncHttpServerResponse response, String contentType, Map<String, String> customHeads) {
        response.setContentType(contentType);
        if (!Tool.isEmpty(customHeads)) {
            for (Map.Entry<String, String> entry : customHeads.entrySet()) {
                response.getHeaders().set(entry.getKey(), entry.getValue());
            }
        }
    }
}

代码中很多是业务,所以大家主要是参照setUp方法和get,post是怎么设置的。
另:
下载的jar包是2.1.6的。但用在项目中遇到
问题一:有乱码。解决方案:项目里的 Charsets.US_ASCII 都改成了 Charsets.UTF_8
问题二: 从客户端获取数据不完整。发现是LineEmitter 类的onDataAvailable(DataEmitter emitter, ByteBufferList bb)内的代码走不通。就把原来的:
@Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { while (bb.remaining() > 0) { byte b = bb.get(); if (b == '\n') { assert mLineCallback != null; mLineCallback.onStringAvailable(data.toString()); data = new StringBuilder(); return; } else { data.append((char)b); } } }
改成了:
@Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { String s = bb.readString(); if (s.indexOf("\n") > 0) mLineCallback.onStringAvailable(s); }}
就OK了
由于我用的是jar包的引用方式,所以是依照上面改动原项目后导出了jar包,导jar包方法:http://blog.csdn.net/u012319317/article/details/48133463
你可以直接下载我导出的jar包:http://download.csdn.net/detail/u012319317/9408485
或者查看源码:github: https://github.com/hjm1fb/AndroidAsync
获取的结果中,中文乱码 更简洁的方案

另:
推荐一篇NIO科普文:
Java NIO:浅析I/O模型

更多参考:
AndroidAsync方案:
An HTTP server inside your Android application using AndroidAsync
This project includes a few examples on how to create different types of sockets using AndroidAsync. It includes examples for a TCP client/server, TCP client with SSL and UDP client/server.
WifiTransfer

其他方案:
AndServer
android-http-server
nanohttpd

Android
Web note ad 1