package org.moonforest.pleasewakeup.httpserver; import android.net.Uri; import android.text.TextUtils; import org.moonforest.pleasewakeup.MyApplication; import org.moonforest.pleasewakeup.RedirectActivity; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * Created by ljian on 17/8/18. */ public class SimpleHttpServer { public static final String URL_PATH = "wakeup"; private static final String CRLF = "\r\n"; private static final String HEADER_BODY_SEP = CRLF + CRLF; private static final String SERVER_NAME = "PleaseWakeUpSimpleHttpServer"; private static final SimpleHttpServer sSimpleHttpServer = new SimpleHttpServer(); private Thread mMainThread; public static SimpleHttpServer getInstance() { return sSimpleHttpServer; } public void stopHttpServer() { if (isServerAlive()) { mMainThread.interrupt(); mMainThread = null; } } private boolean isServerAlive() { return mMainThread != null && mMainThread.isAlive(); } public void startHttpServer() { if (isServerAlive()) { return; } for (int port : new int[]{61593, 41123, 43387, 39083, 24423, 16834, 9289, 8452, 6217, 5300, 4118, 3787, 2998, 0}) { try { ServerSocket localServer = new ServerSocket(port); int localPort = localServer.getLocalPort(); if (localPort <= 0) { continue; } mMainThread = new MainThread(localServer); mMainThread.start(); break; } catch (IOException e) { e.printStackTrace(); } } } private class MainThread extends Thread { private boolean mIfStop = false; private ServerSocket mServerSocket; public MainThread(ServerSocket serverSocket) { mServerSocket = serverSocket; } public void run() { while (!mIfStop) { try { Socket s = mServerSocket.accept(); handleConnection(s); } catch (IOException e) { e.printStackTrace(); } } } @Override public void interrupt() { super.interrupt(); try { mServerSocket.close(); } catch (IOException e) { e.printStackTrace(); } mIfStop = true; } private void handleConnection(final Socket connection) { new Thread(new Runnable() { @Override public void run() { try { doHandleConnection(connection); } catch (IOException e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } finally { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } private void doHandleConnection(Socket connection) throws IOException { StringBuffer sb = new StringBuffer(); int bytesRead = 0; byte[] bytes = new byte[8096]; while ((bytesRead = connection.getInputStream().read(bytes)) != -1) { String msg = new String(bytes, 0, bytesRead); sb.append(msg); if (sb.toString().contains(HEADER_BODY_SEP)) {//读完header为止 break; } if (mIfStop) { return; } } String requestStr = sb.toString(); if (TextUtils.isEmpty(requestStr)) { return; } String path = requestStr.split(" ")[1]; String queryString = path.substring(path.indexOf("?") + 1); String[] args = queryString.split("&"); Uri uri = Uri.parse(path); String firstPath = uri.getPathSegments().get(0); if (firstPath.equalsIgnoreCase(URL_PATH)) {//唤醒用,这里最好对请求做一些验证,防止被误触发或者攻击 String url = uri.getQueryParameter("r"); response(connection, "wakeup success".getBytes()); RedirectActivity.launch(MyApplication.sMyApplication, url); } else if (firstPath.equalsIgnoreCase("test")) {//这段只是测试在微信浏览器里面打开H5页面用的,实际项目里就是着陆页 response(connection, getTestPageContent()); } else { response(connection, "404".getBytes()); } } private byte[] getTestPageContent() { InputStream is = null; try { is = MyApplication.sMyApplication.getAssets().open("test.html"); byte[] bytes = new byte[8096]; int count; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((count = is.read(bytes)) != -1) { baos.write(bytes, 0, count); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return new byte[0]; } private void response(Socket connection, byte[] body) throws IOException { connection.getOutputStream().write(("HTTP/1.1 " + 200 + " OK" + CRLF).getBytes()); connection.getOutputStream().write(("Content-Length: " + body.length + CRLF).getBytes()); connection.getOutputStream().write(("Content-Type: text/html;charset=UTF-8" + CRLF).getBytes()); connection.getOutputStream().write(("Access-Control-Allow-Origin: *" + CRLF).getBytes());//注意这个参数需要跨域 connection.getOutputStream().write(("Server: " + SERVER_NAME + HEADER_BODY_SEP).getBytes()); connection.getOutputStream().write(body); } } }