Android之瀏覽器作爲客戶端訪問手機socket作爲服務端下載圖片和網頁和APK

1 需求

在同一局域網內,手機(PC端)瀏覽器作爲客戶端,然後手機app裏面通過socket寫服務代碼,然後瀏覽器訪問手機服務端的網頁和圖片和css文件和下載APK 

 

 

 

 

 

2 代碼實現

創建服務線程代碼

 var serverSocket: ServerSocket? = null
    var run = true
    inner class HttpServerThread : Runnable {
        var TAG = javaClass.name
        var context : Context?= null

        constructor(context : Context){
            this.context = context
        }
        override fun run() {
            Log.i(TAG, "await start")
            try {
                //Android9.0以下開啓了熱點服務器的IP值是192.168.43.1,如果Android版本大於9.0 IP服務器地址會隨機變
                serverSocket = ServerSocket(SocketContants.HTTP_SERVER_PORT)
//            serverSocket = ServerSocket(SocketContants.HTTP_SERVER_PORT, 10, InetAddress.
//            ("192.168.43.1"))
            } catch (e: IOException) {
                Log.i(TAG, "has error")
                e.printStackTrace()
            }
            if (serverSocket == null) {
                Log.i(TAG, "serverSocket == null")
                return;
            }
            while (run) {
                Log.i(TAG, "while (true) start")
                var socket: Socket? = null
                var input: InputStream? = null
                var output: OutputStream? = null
                try { //接收了客戶端發來的請求,否則一致是等待狀態
                    Log.i(TAG, "serverSocket.accept() start")
                    socket = serverSocket!!.accept()
                    Log.i(TAG, "serverSocket.accept() after")
                    input = socket.getInputStream()
                    output = socket.getOutputStream()
                    // create Request object and parse
                    val request = Request(input)
                    request.parse() //從請求中讀取內容
                    Log.i(TAG, "shutdown.req=" + request.uri)
                    val response = Response(output, context)
                    response.setRequest(request)
                    response.sendDataToClient()
                    socket.close()
                } catch (e: Exception) {
                    e.printStackTrace()
                    Log.i(TAG, "Exception has error ")
                }
            }
        }
    }

開啓服務代碼

Thread(context?.let { HttpServerThread(it) }).start()

在onDestroy裏面關閉服務代碼

        //關閉socket
        if (serverSocket != null) {
            Log.i(TAG, "serverSocket != null and close")
            serverSocket!!.close()
        }
        run = false
Request.java代碼


import android.util.Log;

import java.io.IOException;
import java.io.InputStream;

public class Request {
    public static final String TAG = "Request";
    private static final int SIZE = 2048;
    private InputStream input;
    private String uri;

    public Request(InputStream input) {
        this.input = input;
    }

    public void parse() {
        StringBuffer request = new StringBuffer(SIZE);
        int i;
        byte[] buffer = new byte[SIZE];
        try {
            i = input.read(buffer); //將從輸入流取2048長度的內容存到buffer字節數組中,如果內容不到2048,數組其他空間剩餘空着
        } catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }
        for (int j = 0; j < i; j++) {
            request.append((char) buffer[j]);
        }
        Log.i(TAG, "************Http-request*****************");
        Log.i(TAG, request.toString());
        uri = parseUri(request.toString().replace('/', '\\'));
        Log.i(TAG, "uri is:" + uri);
    }

    private String parseUri(String requestString) {
        int index1, index2;
        index1 = requestString.indexOf(' ');
        Log.i(TAG, "index1 is:" + index1);
        /*
         * http請求行的結構:方法 統一資源標識符(URI) 協議/版本(它們之間以空格分隔)
         * 例如:POST //examples/default.jsp HTTP/1.1
         */
        if (index1 != -1) {// index1 == -1表示沒找到
            index2 = requestString.indexOf(' ', index1 + 1);//從index+1位置開始尋找‘ ’
            Log.i(TAG, "index2 is:" + index2);
            if (index2 > index1)
                return requestString.substring(index1 + 1, index2);
        }
        return null;
    }

    public String getUri() {
        return uri;
    }
}
Response.java代碼

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



import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Response {

    public static final String TAG = "Response";
    private static final int BUFFER_SIZE = 1024;
    public Context conext;
    Request request;
    OutputStream output;
    DataOutputStream sout;

    public Response(OutputStream output, Context conext) {
        this.output = output;
        sout = new DataOutputStream(output);
        this.conext = conext;
    }

    public Response(OutputStream output) {
        this.output = output;
        sout = new DataOutputStream(output);
    }

    public void setRequest(Request request) {
        this.request = request;
    }

    public void sendDataToClient() {
        String url = request.getUri();
        Log.i(TAG, "url is:" + url);
        if (url != null && "\\".equals(url)) {
            //發送apk
//            sendAPK(Constants.APK_NAME);
            sendHtml();
//            sendImage();
        } else if (url != null && url.contains("png")){
            sendImage();
        } else if (url != null && url.contains("css")){
            String cssName = getRequestFileName(url);
            Log.i(TAG, "css Name is" + cssName);
            sendCss(cssName);
        } else if (url != null && url.contains("apk")) {
            sendAPK(Constants.APK_NAME);
        }
    }

    /**
     * 解析url url is:\192.168.43.1:9999\download.css url is:\  url is:\192.168.43.1:9999\ic_launcher_round.png
     */
    public String getRequestFileName(String url) {
        if (TextUtils.isEmpty(url)) {
            return null;
        }
        String ss = "\\\\";
        String[] paths = url.split(ss);
        if (paths == null || paths.length == 0) {
            Log.i(TAG, "paths is null");
            return "";
        }
        String name = paths[paths.length - 1];
        Log.i(TAG, "getNameByImagePath name is:" + name);
        return name;
    }

    public void sendHtml() {
        try {
            String line="HTTP/1.1 200 OK \r\n";
            Log.i(TAG,"line="+line);
            sout.write(line.getBytes());//用字節傳輸,不能用字符,瀏覽器無法解析
            byte[] buff = new byte[1024];
            conext.getAssets().open("share/download.html").read(buff);
            String header="Content-Type: text/html; charset=utf-8 \r\n"
                    +"Content-length: "+ buff.length +" \r\n\r\n";
            Log.i(TAG,"header="+header);
            sout.writeBytes(header);
            sout.write(buff);
            sout.flush();
            sout.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sout != null)
                try {
                    sout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public void sendCss(String fileName) {
        try {
            String line="HTTP/1.1 200 OK \r\n";
            Log.i(TAG,"line="+line);
            sout.write(line.getBytes());//用字節傳輸,不能用字符,瀏覽器無法解析
            byte[] buff = new byte[1024 * 100];
            conext.getAssets().open("share/" + fileName).read(buff);
            String header="Content-Type: text/css; charset=utf-8 \r\n"
                    +"Content-length: "+ buff.length +" \r\n\r\n";
            Log.i(TAG,"header="+header);
            sout.writeBytes(header);
            sout.write(buff);
            sout.flush();
            sout.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sout != null)
                try {
                    sout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public void sendImage() {
        try {
            String line="HTTP/1.1 200 OK \r\n";
            Log.i(TAG,"line="+line);
            sout.write(line.getBytes());//用字節傳輸,不能用字符,瀏覽器無法解析
            byte[] buff = new byte[1024 * 100];
            conext.getAssets().open("share/ic_launcher_round.png").read(buff);
            String header="Content-Type: image/jpeg; charset=utf-8 \r\n"
                    +"Content-length: "+ buff.length +" \r\n\r\n";
            Log.i(TAG,"header="+header);
            sout.writeBytes(header);
            sout.write(buff);
            sout.flush();
            sout.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sout != null)
                try {
                    sout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }

    public void sendAPK(String fileName)  {

        FileInputStream fis = null;
        try {
            Log.i(TAG, "request.getUri() is:" + request.getUri());
            String apkPath = SPHelper.getInstance().getString(SpConstants.CURRENT_APK_PATH, "");
            Log.i(TAG, "apkPath is:" + apkPath);
            if (TextUtils.isEmpty(apkPath)) {
                sendHtml();
                return;
            }
            File file = new File(apkPath);
//            File file = new File("/storage/emulated/0/my.html");
            Log.i(TAG, "*************Http-response****************");
            if (file != null && file.exists()) {
                String line="HTTP/1.1 200 OK \r\n";
                Log.i(TAG,"line="+line);
                //sout.writeChars(line);
                sout.write(line.getBytes());//用字節傳輸,不能用字符,瀏覽器無法解析
//                String header="Content-Type: application/vnd.android.package-archive; charset=utf-8 \r\n"
                String header="Content-Type: application/octet-stream; charset=utf-8 \r\n"
                        + "Content-Disposition: attachment; filename=" + fileName+ "\r\n"
                        + "Content-length: "+file.length()+" \r\n\r\n";
                Log.i(TAG,"header="+header);
                sout.writeBytes(header);
                fis = new FileInputStream(file);
                /**
                byte[] bytes = new byte[BUFFER_SIZE];
                int ch = fis.read(bytes, 0, BUFFER_SIZE);;
                while (ch!=-1) { //ch==-1表示讀到末尾了
                    sout.write(bytes, 0, ch); //寫出到瀏覽器
                    Log.i(TAG, "ch is:" + ch);
                    ch = fis.read(bytes, 0, BUFFER_SIZE);//再讀會接上一次讀的位置往下讀,如果讀到末尾就會返回-1,終止輸出
                } **/
                byte[] buff = new byte[1024];
                int size;
                while ((size = fis.read(buff)) != -1) {
                    Log.i(TAG, "size is:" + size);
                    sout.write(buff, 0, size);
                }
                sout.flush();
                sout.close();
                fis.close();
            } else {
                // file not found
                String errorMessage = "HTTP/1.1 404 File Not Found \r\n"
                        + "Content-Type: text/html \r\n"
                        + "Content-Length: 23 \r\n"
                        + "\r\n"
                        + "<h1>File Not Found</h1>";
                System.out.println(errorMessage);
                output.write(errorMessage.getBytes());
            }
        } catch (Exception e) {
            Log.i(TAG, "sendAPK apk has error");
            e.printStackTrace();
        } finally {
            Log.i(TAG, "finally here.............");
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (sout != null) {
                try {
                    sout.flush();
                    sout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

這個APK的路徑是當前APK在手機裏面的路徑,然後css和html和image圖片放在assets目錄下的share目錄

******\app\src\main\assets\share\

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章