使用的框架是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 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 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 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 getFilesSortedByLastModified(String path) {
List 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() {
@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 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 {
@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 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 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 customHeads) {
response.setContentType(contentType);
if (!Tool.isEmpty(customHeads)) {
for (Map.Entry 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
获取的结果中,中文乱码 更简洁的方案
另:
推荐一篇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