Android 經常使用開源框架源碼解析 系列 (二)網絡框架之一 OkHttp雜題

一、Android基礎網絡編程:socket、HttpClient、HttpURLConnection
    1.1 Socket 定義
    是一個對TCP/IP協議進行封裝的編程調用接口,自己不是一種協議是接口Api!!
    成堆出現,一對套接字:包括ip地址和端口號
 
    基於應用層和傳輸層抽象出來的一個層。App能夠經過該層發送、接收數據,並經過Socket將App添加到網絡當中
    簡單來講就是應用與外部通訊的端口,提供了兩端數據的傳輸的通道
 
    1.2 Socket通訊模型
    基於TCP和UDP協議的兩種模型
  •     TCP:採用字節流協議來提供可靠的字節流服務
  •     UDP:採用數據報文的形勢提供數據,打包的形勢發送服務
 
    1.3 Socket與Http對比
     Android與服務器的通訊方式
    (1)Http通訊
        基於請求-響應方式; 屬於應用層解決如何包裝數據的問題
    (2)Socket通訊
        採用服務器主動發送數據的方式, Socket屬於傳輸層;解決數據如何在網絡中傳輸
 
    1.4 Socket實現
/**
* Tcp 客戶端Socket
*/
public void TcpSendMessage(String msg) {
    Socket socket = null;
    OutputStream outputStream = null;
    InputStream inputStream = null;
    try {
        //一、建立客戶端Socket對象,傳入目標主機名orId地址和端口號
        socket = new Socket("192.168.1.1", 8080);
        //二、經過socket獲取輸出流
        outputStream = socket.getOutputStream();
        //三、寫入輸出流操做
        outputStream.write(msg.getBytes());
        //四、關閉socket操做,msg寫入結束 ps:不調用會形成服務器端消息返回的沒法獲取
        socket.shutdownOutput();
        //五、msg的IO流讀取操做
        inputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        int len = -1;
        final StringBuffer sb = new StringBuffer();
        while ((len = inputStream.read(b)) != -1) {
            sb.append(new String(b, 0, len, Charset.forName("gbk")));
        }
        //todo 在主線程中更新Ui
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //注意,輸出流不須要關閉,由於它不是建立的而是經過Socket中獲得輸出流對象獲取的
        if ((socket != null)) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
* Tcp 服務器Socket
*/
public void ServerMessage() {
    ServerSocket server = null;
    Socket socket = null;
    try {
        //一、建立服務器Socket對象並監聽須要的端口號
        server = new ServerSocket(8888);
        while (true) {
            //二、接收客戶端發送的請求;ps:若客戶端沒有發送數據,該線程會停滯,accept中會阻塞
            socket = server.accept();
            //三、獲取輸入流
            InputStream inputStream = socket.getInputStream();
            //四、建立緩存輸入流進行數據的讀入
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = bis.read()) != -1) {
                System.out.println(new String(b, 0, len, "UTF-8"));
            }
            socket.shutdownInput();
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("收到".getBytes());
 
            bis.close();
            socket.close();//serverSocket不能被關閉!
            socket = null;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1.4 HttpClient 和 HttpURLConnection
基本的HttpURLConnection連接  一個簡單Get實例:
/**
* HttpURLConnection
*/
public static void readContentFromGet() throws IOException {
    //一、拼接get請求字符串
    String getURL = "GET_URL" + "?username= " + URLEncoder.encode("fat-man", "UTF-8");
    //二、建立URL對象
    URL getUrl = new URL(getURL);
    //三、代表這個connection只能發送一個請求
    HttpURLConnection connection = (HttpURLConnection)  getUrl .openConnection();
    //四、創建連接,這時並無將真正請求發送給服務器端
     connection .connect();
    //取得輸入流,並使用Reader讀取,getInputStream()方法將真正的請求發送給服務器端
    BufferedReader reader = new BufferedReader(new InputStreamReader
            ( connection .getInputStream()));
    String lines;
    while ((lines = reader.readLine()) != null) {
        System.out.println(lines);
    }
     reader .close();
    //斷開連接,關閉底層Socket連接
     connection .disconnect();
}
 
二、瞭解WebSocket?知道和Socket的區別?OkHttp是如何處理WebSocket的相關問題
 
    2.1 WebSocket
    推送- 輪詢 是特定的時間間隔,由瀏覽器對服務器發送Http請求,而後由服務器返回最新的數據給客戶端的瀏覽器
 
短輪詢
提交表單的形勢進行數據傳遞;
     缺陷:在某個時間段Server沒有更新數據,但Client端仍然每隔一段時間發送請求來詢問,因此這段時間內的詢問都是無效的,冗餘數據。
 
長輪詢
    服務器端接收request請求後不會當即返回數據response給客戶端,會檢查數據是否有更新。若是有更新了就會返回給客戶端數據,若是沒有更新則不返回。
 
缺陷:
  •             浪費帶寬 
  •             Http Head 過大實際body缺不大
  •             消耗服務器CPU佔用
 
WebSocket
  WebSocket一旦創建了兩端的鏈接,能夠不斷的進行通訊,是一種全雙通的通訊模式。
 
    2.2 WebSocket 與Http
Http是 懶惰的協議,有接收纔有響應
WebSocket是全雙向通訊網絡協議,server主動向client發送數據
 
   2.3 WebSocket 與Socket
Socket 首先要明白是一種接口 並非一貫協議
WebSocket是同等級的網絡協議
二者沒有任何關係
    
  •     本質上是一個基於TCP的協議
  •     向服務器發起一個HTTP請求 /「Upgrade WebSocket」
  •     服務器端解析頭信息
   
 2.4 OkHttp是如何處理WebSocket的
        
   private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };
 
    /**
     * WebSocketListener 運行在工做線程的
     */
    private final class EchoWebSocketListener extends WebSocketListener {
 
        //WebSocket 和遠程 服務器端創建連接
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
//            super.onOpen(webSocket, response);
            //OkHttp使用本身的後臺發送數據,不用擔憂sendMessage1會阻塞當前線程的問題
            webSocket.send("xxx");
            //發送消息已經完成
            webSocket.close(1000, "ss");
        }
 
        /**
         * onMessage()中與主線程的交互要很是很是當心!!與主線程用handler交互能夠
         */
        @Override
        public void onMessage(WebSocket webSocket, String text) {
//            super.onMessage(webSocket, text);
            setText("onMessage :" + text);
            handler.sendEmptyMessage(0);
        }
 
        //遠端已經沒有數據的狀況,準備關閉WebSocket連接可是尚未關閉
        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) {
//            super.onClosing(webSocket, code, reason);
            setText("onClosed:" + code + "/" + reason);
        }
 
        //這個連接已經徹底被關閉了
        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
//            super.onClosed(webSocket, code, reason);
            setText("onClosed:" + code + "/" + reason);
        }
 
        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
//            super.onFailure(webSocket, t, response);
            setText("onFailure:" + t + "/" + response);
        }
    }
 
三、Http如何處理緩存?OkHttp如何處理緩存相關問題?
 
  • 強制緩存
(1)Expires 過時時間 —Http1.0 
    值表示服務器端返回的到期時間;
    下一次請求時候,請求的時間 <  服務端返回的到期時間 —》會直接使用緩存數據
缺陷:
    到期時間是由服務器端生成的,會與客戶端的時間形成偏差
 
(2)Cache-Control
    Cache-control 是由 服務器返回的Response中添加的頭信息;
     做用是告訴用戶是從本地讀取緩存仍是從服務端獲取消息
 
Cache-Control的取值:   
  •         private :表示客戶端能夠取緩存
  •         public  :表示客戶端和代理服務器均可以緩存
  •         max-age:表示緩存內容在多少秒後失效
  •         no-cache:表示強制緩存的標識沒法處理緩存
  •         no-store:表示不進行緩存
 
  • 對比緩存——網絡協議
 
    一、首先須要進行比較判斷是否可使用緩存
    二、服務器會將緩存標識與數據一塊兒返回給客戶端
 
流程:
    再次請求數據——>
            if(有緩存 != null) {
                    if(是否過時 ?){
                            沒過時直接從緩存讀取數據
                      }else if( 沒法判斷是否已通過期){
                       // 進行對比緩存檢查
                                if(判斷ETag 標準){
                                  向web服務器請求帶If-None-Match—— 二者進行匹配!     
                                       資源 有改動返回200,請求響應; 無改動返回304 直接從緩存讀取    
                                  }else if(ETag != null){
                                    if(Last-Modified == null ){
                                        向服務器請求帶If-Modified-Since
                                            有改動返回200 ,請求響應;無改動返回304 直接從緩存讀取
                                    }
                                 }
                      }
             }
    
 
當前資源是否被改動過,改動過返回200,再去請求響應,沒有改動過返回304
 
ETag / If-None-Match 成對出現
 
  • ETag   :            服務器端響應請求時候,告訴瀏覽器當前資源在服務器的惟一標識
   ps:生成規則由服務器端決定惟一標識 與下面的進行匹配
 
  • If-None-Match:再次請求服務器時候,經過此字段通知服務器客戶端緩存數據的惟一標識
 
Last-Modified / If-Modefied-Since 成對出現
 
  • Last-Modified    :   服務器在響應請求時,告訴瀏覽器資源的最後修改時間
  • If-Modefied-Since :再次請求服務器時,瀏覽器通知服務器端上次請求時,服務器返回的資源最後修改時間
 
 
四、斷點續傳的原理?如何實現?OkHttp中如何實現相關原理?
    4.1 斷點續傳
   斷點續傳:從文件已經下載完的地方開始繼續下載
    實現:客戶端發送給瀏覽器端的請求頭報文當中,添加此次下載從什麼位置開始的新條件
RANGE:bytes = 200080 - 
        代表此次從 資源的 200080位置開始下載
 
在Java中用HttpURLConnection 實現:
public void doBreakDownLoadJava() {
    URL url = null;
    try {
        //一、建立URL對象
        url = new URL(" http://www.sjtu.edu.cn/down.zip");
          //二、經過URL建立 HttpURLConnection,由它完成網絡請求
        HttpURLConnection httpURLConnection = (HttpURLConnection)  url .openConnection();
        //三、經過setRequestProperty ,建立請求頭部信息,設置斷點續傳的開始位置
        httpURLConnection. setRequestProperty("RANGE", "bytes=2000080」);
        InputStream inputStream = httpURLConnection.getInputStream();
          //四、獲取到流信息保存到文件中,用字節進行指定的讀取
        RandomAccessFile oSaveFile = new  RandomAccessFile("down.zip", "rw");
        long nPos = 2000070;
         //五、代表文件讀取的位置
         oSaveFile .seek(nPos);
        //常規IO流讀寫操做
        byte[] b = new byte[1024];
        int nRead;
        while ((nRead = inputStream.read(b, 0, 1024)) > 0) {
          //六、對文件寫入操做
            oSaveFile. write(b, 0, nRead);
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
 
OkHttp中相關實現實例:
/**
* OkHttp斷點續傳
*/
public void doDownloadWithOkHttp() {
    InputStream is = null;
    RandomAccessFile savedFie = null;
    File file;
    //一、首先記錄已經下載的文件長度
    long downloadLength = 0;
    String downloadUrl = "www.baidu.com/wenku/o2232.txt";
    String filename = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
    File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    file = new File(directory + filename);
   //二、判斷下載的文件是否存在 ,存在的話下載長度範圍賦值
    if (file.exists()) {
        downloadLength = file.length();
    }
    long contentLength = getContentLength(downloadUrl);
    //三、建立OkHttpClient對象
    OkHttpClient client = new OkHttpClient();
   //四、建立Request對象,經過addHeader加頭部信息添加到請求裏,代表下載的範圍
    Request request = new Request.Builder()
            .addHeader("RANGE", "bytes=" + downloadLength + "-")
            .url(downloadUrl)
            .build();
    //五、開啓一個同步請求
    try {
        Response response = client.newCall(request).execute();
        //六、根據Response進行判斷
        if (request != null) {
            is = request.body().byteStream();
            savedFie = new RandomAccessFile(file, "rw");
            //七、跳過已經下載的字節
            savedFie.seek(downloadLength);
            byte[] b = new byte[1024];
            int total = 0;
            int len;
            while ((len = is.read()) != -1) {
                total += len;
                savedFie.write(b, 0, len);
               //八、計算已經下載的百分比
                int progress = (int) ((total + downloadLength) * 100 / contentLength);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
 
五、多線程下載原理,OkHttp如何實現?
 
多線程下載:每一個線程只負責下載文件的一部分,也就是分段加載。
5.1 Java中多線程
在Java中多線程的下載 實例:
    
    /**
     * 多線程下載
     */
   public void download() throws Exception {
        URL url = new URL(path);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(10000);
       //根據connection的ResponseCode來進行相應的操做
        int code = connection.getResponseCode();
        if (code == 200) {
            //獲取資源文件大小
            int connectionLength = connection.getContentLength();
            //在本地建立一個與資源一樣大小的文件來佔位
            RandomAccessFile randomAccessFile = new RandomAccessFile(
                    new File(targetfilePath, getFilePath));
            //在本地建立一個佔位文件
            randomAccessFile.setLength(connectionLength);
 
            //計算每個線程加載的數量
            int blockSize = connectionLength / threadCount;
            //爲每個線程分配任務
            for (int threadId = 0; threadId < threadCount; threadId++) {
                //線程開始/結束下載的位置
                int startIndex = threadId * blockSize;
                int endIndex = (threadId + 1) * blockSize - 1;
                if (threadId == (threadCount - 1)) {
                   //將全部任務交給endIndex完成
                    endIndex = connectionLength - 1;
                }
                //開始正式多線程的實現
                new DownloadThread(threadId, startIndex, endIndex).start();
            }
            randomAccessFile.close();
        }
    }
 
    /**
     * 開始正式多線程的實現
     */
   private class DownloadThread extends Thread {
        private int threadID, startIndex, endIndex;
 
        public DownloadThread(int threadID, int startIndex, int endIndex) {
            this.threadID = threadID;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }
 
        @Override
        public void run() {
            System.out.println("線程" + threadID + "開始下載");
            try {
                //一、分段下載也須要分段的獲取URL 將文件保存到本地
                URL url = new URL(path);
                //二、加載下載位置的文件,獲取文件大小
                File downThreadFile = new File(targetFilePath, "downThread_" + threadID + ".dt");
                //三、建立一個新的RandomAccessFile
                RandomAccessFile downThreadStream = null;
                if (downThreadFile.exists()) {
                    //四、若是文件不存在
                    downThreadStream = new RandomAccessFile(downThreadFile, "rwd");
                    String startIndex_str = downThreadStream.readLine();
                    if (startIndex_str != unll || !"".equals(startIndex_str)) {
                        this.startIndex = Integer.parseInt(startIndex_str) - 1;//下載起點
                    }
                } else {
                    downThreadStream = new RandomAccessFile(downThreadFile, "rwd");
                }
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(10000);
               //五、設置分段下載頭信息
                connection.setRequestProperty("RANGE", "bytes=" + startIndex + "-" + endIndex);
                if (connection.getResponseCode() == 206) {//六、部分資源請求成功
                    InputStream inputStream = connection.getInputStream();
                    //七、獲取建立的文件
                    RandomAccessFile randomAccessFile = new RandomAccessFile(
                            new File(targetFilePath, getFileName(url), "rw")
                    );
                    //八、文件寫入的計算位置
                    randomAccessFile.seek(startIndex);
                   //IO流讀寫操做
                    byte[] buffer = new byte[1024];
                    int length = -1;
                    int total = 0;//記錄本次下載文件的大小
                    while ((length = inputStream.read(buffer)) > 0) {
                        randomAccessFile.write(buffer, 0, length);
                        total += length;
                        downThreadStream.seek(0);
                        downThreadStream.write((startIndex + total + "").getBytes("UTF-8"));
                    }
                    //九、關閉IO流操做
                    downThreadStream.close();
                    inputStream.close();
                    randomAccessFile.close();
                    cleanTemp(downThreadFile);//刪除建立的佔位臨時文件
                    System.out.println("線程:" + threadID + "下載完畢");
                } else {
                    System.out.println("響應碼:" + connection.getResponseCode() + "服務器不支持");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
 
5.2 OkHttp 多線程下載的實現:
    
/**
* OkHttp斷點續傳
*/
public void doDownloadWithOkHttp() {
    InputStream is = null;
    RandomAccessFile savedFie = null;
    File file;
   //一、記錄已經下載的文件長度
    long downloadLength = 0;
    String downloadUrl = "www.baidu.com/wenku/o2232.txt";
    String filename = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
    File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    file = new File(directory + filename);
    if (file.exists()) {
        downloadLength = file.length();
    }
    long contentLength = getContentLength(downloadUrl);
    //二、建立OkHttpClient對象
    OkHttpClient client = new OkHttpClient();
    //三、建立Request對象,經過addHeader加頭部信息添加到請求裏,代表下載的範圍
    Request request = new Request.Builder()
            .addHeader("RANGE", "bytes=" + downloadLength + "-")
            .url(downloadUrl)
            .build();
    //四、開啓一個同步請求
    try {
        Response response = client.newCall(request).execute();
        //五、根據Response進行判斷
        if (request != null) {
            is = request.body().byteStream();
            savedFie = new RandomAccessFile(file, "rw");
            //六、跳過已經下載的字節
            savedFie.seek(downloadLength);
            byte[] b = new byte[1024];
            int total = 0;
            int len;
            while ((len = is.read()) != -1) {
                total += len;
                savedFie.write(b, 0, len);
                //七、計算已經下載的百分比
                int progress = (int) ((total + downloadLength) * 100 / contentLength);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
 
六、文件上傳如何作?原理?OkHttp如何完成文件上傳
     6.1 文件上傳
 Java中的文件上傳 :在UrlConnection中使用post方法 而後在請求頭時候添加Http之 Content-Type
指定請求和響應的HTTP內容類型 ,好比:
    Content-Type :  multipart / form-data;
     boundary = ———(分割數據)WebkKitFormBoundaryOGKWPJsJCPWjZP
 
     6.2 OkHttp 文件上傳的簡單操做
public <T> void upLoadFile( String actionUrl ,HashMap<String,Object> paramsMap){
String requestUrl = String.format (「%s/%s」,」upload」,cationUrl);
//0、經過MultipartBody建立文件上傳的body體
MultipartBody.Builder builder = new MultipartBody.Builder()
.addPart(Headers.of(
         "Content-Disposition", 
         "form-data; name=\"mFile\"; 
         filename=\"1.txt\""), fileBody)
     .build();
;
    builder.setType(MultipartBody.FORM);
    for (String key : paramsMap.keySet() ){
        Object object =paramsMap.get(key);
            if( ! ( object instanceof File) ){
                builder.addFormDataPart (key, object.toString() );
            } else {
                File file = (File)object ;
                builder .addFormDataPart(key,file.getName(),
                                RequestBody.create(MediaType.parse( application/octet-stream )) );
            }    
        }
    //一、構建RequestBody
    RequestBody body = builder.build();
    //二、構建Request
    Request request = new Request.Builder().url(「…」).post(body).build();
    //三、構建Call
    Call call = client . newBuilder().writeTimeout(60,TimeUnit.xxx);
    //四、構建異步回調
        call.enqueue(new Callback(){
            ...
        });
 
 
七、json數據如何解析?OkHttp如何解析json類型數據
    7.1 json數據的JAVA 解析
json:文本形式的數據交換格式
 
一、傳統的JSON解析——— JSObject和JSArray
二、GSON————
三、FastJSON——
 
GSON 的兩種解析方式:
/**
** 將json數據解析成list
*/
public void doGson(){
    //構建Gson對象
   Gson gson = new Gson();
    //經過fromJson 實現反序列化
      List<T> list =  gson.fromJson(jsonData ,new TypeToken<List<T>>(){}.getType());
}
 
public void doGson(){
    //一、構建JsonParser 解析對象
 JsonParser parser = new JsonParser();
     //二、經過解析對象 將String類型json數組轉化成JsonArray
JsonArray jsonArray  = parser .parse (stringjson).  getAsJsonArray():
     //三、構建Gson對象 list對象
    Gson gson = new Gson();
    ArrayList<T> list = new ArrayList<>();
    //四、開始一個for循環 循環遍歷jsonArray,獲取jsonArray的每個元素
for ( JsonElement je : jsonArray ){
     T  t1 = gson . fromJson(je , T.class);
        list .add ( t1) ;
    }
}
 
7.2 OkHttp中的json解析
    a、封裝一個工具類HttpUtil
        public class HttpUtil {
            public static void sendOkHttpRequest (final String address ,final okhttp3.Callback callback){
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder().url(address).build();
                client.newCall(request).enqueue(callback);
    b、在響應中的調用
        private void sendRequestWithOkHttp(){
            new Thread(new Runnable(){
                @Override
                public void run(){
                    //子線程中執行http請求,並將最終的請求結果回調到Callback中
                    HttpUtil.sendOkHttpRequest( url, new okhttp3.Callback(){
                        @Override
                       public void onResponse(Call call, Response response) throws IOException{
                               String responseData = response.body().string();
                               //解析json數據
                                parseJsonWithGson(responseData);
                                //顯示UI界面,通知主線程更新ui
                                showResponse( responseData.toString() );
                           }
                        @Override
                       public void onFailure(Call call ,IOException e){
                           }
                   )};
                  }
            }).start();
    }
private void parseJsonWithGson (String jsonData){
     //使用輕量級的Gson解析獲得json
    Gson gson = new Gson();
    List<T> list = gson.fromJson(jsonData ,new TypeToken<List<T>>(){}.getType());
}
private void showResponse (final String response) {
     //在自線程中通知ui更新
    runOnUiThread (new Runnable() {
        @Override
        public void run(){
            //在此進行UI處理操做
            text .setText ( response);
        }
    )};
}
Lambda表達式的操做樣式
    private void showResponse( final String response) {
        runOnUiThread( () -> {
            text.setText (response);
        });
}
 
八、Https協議處理?
 Https協議
    Https是一種基於SSL/TLS的Http協議,是屬於應用層協議;
  •         添加SSL/TLS 握手過程
  •         二者數據加密傳輸
 
全部傳輸的內容都通過加密(對稱加密+不對稱加密)
 
對稱加密
 是指加密和解密使用的密鑰匙同一個密鑰,二者能夠互相推算。 真正傳輸的數據進行加密
 
不對稱加密
    不對稱加密和解密使用的密鑰 不是同一密鑰,對外公開其中一個密鑰叫公鑰。 該加密是用於握手階段的!
 
傳送模式:
對稱加密所使用的密鑰咱們能夠經過非對稱加密的方式發送出去
 
實例:
    一筆交易流程:
一、客戶端生成一個隨機對稱密鑰
二、客戶端向服務器端請求一個公共密鑰 -不對稱加密所須要的公鑰,給外界用的
三、服務端返回公鑰給客戶端
四、客戶端接收到公鑰後,經過該公鑰對本身生成的隨機對稱密鑰進行加密
五、將加密過的對稱密鑰發送給服務端
六、服務端接收該對稱密鑰後會用本身的私鑰對其進行解密
七、進行傳輸 使用對稱加密進行
 
Https 握手過程:
    一、客戶端發起Https連接請求獲取不對稱加密的公鑰(客戶端支持的加密規則發送給服務端--不對稱加密)
    二、服務端接收到請求後,從規則中選出一個不對稱加密算法和一個hash算法(驗證數據完整性的)
    三、服務端將本身的身份信息以證書的形式返回給客戶端 -含有不對稱加密的公鑰
    四、客戶端生成隨機數-對稱密鑰 須要客戶端和服務端雙方保存
    五、客戶端使用不對稱加密的公鑰對 「隨機生成的對稱密鑰 進行加密」
    六、客戶端將加密過的密鑰發送給服務端
    七、服務端經過私鑰對獲取的加密過的密鑰進行解密
    八、以後均是: 經過對稱密鑰加密的密紋通訊 
相關文章
相關標籤/搜索