zoukankan      html  css  js  c++  java
  • Android 常用开源框架源码解析 系列 (二)网络框架之一 OkHttp杂题

    1、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 {
            //1、创建客户端Socket对象,传入目标主机名orId地址和端口号
            socket = new Socket("192.168.1.1", 8080);
            //2、通过socket获取输出流
            outputStream = socket.getOutputStream();
            //3、写入输出流操作
            outputStream.write(msg.getBytes());
            //4、关闭socket操作,msg写入结束 ps:不调用会造成服务器端消息返回的无法获取
            socket.shutdownOutput();
            //5、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 {
            //1、创建服务器Socket对象并监听需要的端口号
            server = new ServerSocket(8888);
            while (true) {
                //2、接收客户端发送的请求;ps:若客户端没有发送数据,该线程会停滞,accept中会阻塞
                socket = server.accept();
                //3、获取输入流
                InputStream inputStream = socket.getInputStream();
                //4、创建缓存输入流进行数据的读入
                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 {
        //1、拼接get请求字符串
        String getURL = "GET_URL" + "?username= " + URLEncoder.encode("fat-man", "UTF-8");
        //2、创建URL对象
        URL getUrl = new URL(getURL);
        //3、表明这个connection只能发送一个请求
        HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
        //4、建立链接,这时并没有将真正请求发送给服务器端
        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();
    }
     
    2、了解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);
            }
        }
     
    3、Http如何处理缓存?OkHttp如何处理缓存相关问题?
     
    • 强制缓存
    (1)Expires 过期时间 —Http1.0 
        值表示服务器端返回的到期时间;
        下一次请求时候,请求的时间 <  服务端返回的到期时间 —》会直接使用缓存数据
    缺陷:
        到期时间是由服务器端生成的,会与客户端的时间造成误差
     
    (2)Cache-Control
        Cache-control 是由服务器返回的Response中添加的头信息;
       作用是告诉用户是从本地读取缓存还是从服务端获取消息
     
    Cache-Control的取值:   
    •         private :表示客户端可以取缓存
    •         public  :表示客户端和代理服务器都可以缓存
    •         max-age:表示缓存内容在多少秒后失效
    •         no-cache:表示强制缓存的标识无法处理缓存
    •         no-store:表示不进行缓存
     
    • 对比缓存——网络协议
     
        1、首先需要进行比较判断是否可以使用缓存
        2、服务器会将缓存标识与数据一起返回给客户端
     
    流程:
        再次请求数据——>
                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 :再次请求服务器时,浏览器通知服务器端上次请求时,服务器返回的资源最后修改时间
     
     
    4、断点续传的原理?如何实现?OkHttp中如何实现相关原理?
        4.1 断点续传
       断点续传:从文件已经下载完的地方开始继续下载
        实现:客户端发送给浏览器端的请求头报文当中,添加这次下载从什么位置开始的新条件
    RANGE:bytes = 200080 - 
            表明这次从 资源的 200080位置开始下载
     
    在Java中用HttpURLConnection 实现:
    public void doBreakDownLoadJava() {
        URL url = null;
        try {
           //1、创建URL对象
            url = new URL("http://www.sjtu.edu.cn/down.zip");
            //2、通过URL创建 HttpURLConnection,由它完成网络请求
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
           //3、通过setRequestProperty ,创建请求头部信息,设置断点续传的开始位置
            httpURLConnection.setRequestProperty("RANGE", "bytes=2000080”);
            InputStream inputStream = httpURLConnection.getInputStream();
            //4、获取到流信息保存到文件中,用字节进行指定的读取
            RandomAccessFile oSaveFile = new RandomAccessFile("down.zip", "rw");
            long nPos = 2000070;
            //5、表明文件读取的位置
            oSaveFile.seek(nPos);
            //常规IO流读写操作
            byte[] b = new byte[1024];
            int nRead;
            while ((nRead = inputStream.read(b, 0, 1024)) > 0) {
             //6、对文件写入操作
                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;
        //1、首先记录已经下载的文件长度
        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);
       //2、判断下载的文件是否存在 ,存在的话下载长度范围赋值
        if (file.exists()) {
            downloadLength = file.length();
        }
        long contentLength = getContentLength(downloadUrl);
        //3、创建OkHttpClient对象
        OkHttpClient client = new OkHttpClient();
       //4、创建Request对象,通过addHeader加头部信息添加到请求里,表明下载的范围
        Request request = new Request.Builder()
                .addHeader("RANGE", "bytes=" + downloadLength + "-")
                .url(downloadUrl)
                .build();
        //5、开启一个同步请求
        try {
            Response response = client.newCall(request).execute();
            //6、根据Response进行判断
            if (request != null) {
                is = request.body().byteStream();
                savedFie = new RandomAccessFile(file, "rw");
                //7、跳过已经下载的字节
                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);
                   //8、计算已经下载的百分比
                    int progress = (int) ((total + downloadLength) * 100 / contentLength);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
     
    5、多线程下载原理,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 {
                    //1、分段下载也需要分段的获取URL 将文件保存到本地
                    URL url = new URL(path);
                    //2、加载下载位置的文件,获取文件大小
                    File downThreadFile = new File(targetFilePath, "downThread_" + threadID + ".dt");
                    //3、创建一个新的RandomAccessFile
                    RandomAccessFile downThreadStream = null;
                    if (downThreadFile.exists()) {
                        //4、如果文件不存在
                        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);
                   //5、设置分段下载头信息
                    connection.setRequestProperty("RANGE", "bytes=" + startIndex + "-" + endIndex);
                    if (connection.getResponseCode() == 206) {//6、部分资源请求成功
                        InputStream inputStream = connection.getInputStream();
                        //7、获取创建的文件
                        RandomAccessFile randomAccessFile = new RandomAccessFile(
                                new File(targetFilePath, getFileName(url), "rw")
                        );
                        //8、文件写入的计算位置
                        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"));
                        }
                        //9、关闭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;
       //1、记录已经下载的文件长度
        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);
        //2、创建OkHttpClient对象
        OkHttpClient client = new OkHttpClient();
        //3、创建Request对象,通过addHeader加头部信息添加到请求里,表明下载的范围
        Request request = new Request.Builder()
                .addHeader("RANGE", "bytes=" + downloadLength + "-")
                .url(downloadUrl)
                .build();
        //4、开启一个同步请求
        try {
            Response response = client.newCall(request).execute();
            //5、根据Response进行判断
            if (request != null) {
                is = request.body().byteStream();
                savedFie = new RandomAccessFile(file, "rw");
                //6、跳过已经下载的字节
                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);
                    //7、计算已经下载的百分比
                    int progress = (int) ((total + downloadLength) * 100 / contentLength);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
     
    6、文件上传如何做?原理?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)) );
                }    
            }
        //1、构建RequestBody
        RequestBody body = builder.build();
        //2、构建Request
       Request request = new Request.Builder().url(“…”).post(body).build();
        //3、构建Call
        Call call = client . newBuilder().writeTimeout(60,TimeUnit.xxx);
        //4、构建异步回调
            call.enqueue(new Callback(){
                ...
            });
     
     
    7、json数据如何解析?OkHttp如何解析json类型数据
       7.1 json数据的JAVA 解析
    json:文本形式的数据交换格式
     
    1、传统的JSON解析——— JSObject和JSArray
    2、GSON————
    3、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(){
        //1、构建JsonParser 解析对象
     JsonParser parser = new JsonParser();
        //2、通过解析对象 将String类型json数组转化成JsonArray
    JsonArray jsonArray  = parser .parse (stringjson). getAsJsonArray():
        //3、构建Gson对象 list对象
        Gson gson = new Gson();
        ArrayList<T> list = new ArrayList<>();
        //4、开始一个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);
            });
    }
     
    8、Https协议处理?
     Https协议
        Https是一种基于SSL/TLS的Http协议,是属于应用层协议;
    •         添加SSL/TLS 握手过程
    •         两者数据加密传输
     
    所有传输的内容都经过加密(对称加密+不对称加密)
     
    对称加密
     是指加密和解密使用的密钥匙同一个密钥,两者可以互相推算。真正传输的数据进行加密
     
    不对称加密
        不对称加密和解密使用的密钥不是同一密钥,对外公开其中一个密钥叫公钥。该加密是用于握手阶段的!
     
    传送模式:
    对称加密所使用的密钥我们可以通过非对称加密的方式发送出去
     
    实例:
        一笔交易流程:
    1、客户端生成一个随机对称密钥
    2、客户端向服务器端请求一个公共密钥 -不对称加密所需要的公钥,给外界用的
    3、服务端返回公钥给客户端
    4、客户端接收到公钥后,通过该公钥对自己生成的随机对称密钥进行加密
    5、将加密过的对称密钥发送给服务端
    6、服务端接收该对称密钥后会用自己的私钥对其进行解密
    7、进行传输 使用对称加密进行
     
    Https 握手过程:
        1、客户端发起Https链接请求获取不对称加密的公钥(客户端支持的加密规则发送给服务端--不对称加密)
        2、服务端接收到请求后,从规则中选出一个不对称加密算法和一个hash算法(验证数据完整性的)
        3、服务端将自己的身份信息以证书的形式返回给客户端 -含有不对称加密的公钥
        4、客户端生成随机数-对称密钥 需要客户端和服务端双方保存
        5、客户端使用不对称加密的公钥对 “随机生成的对称密钥 进行加密”
        6、客户端将加密过的密钥发送给服务端
        7、服务端通过私钥对获取的加密过的密钥进行解密
        8、之后均是: 通过对称密钥加密的密纹通信 
     
  • 相关阅读:
    python操作文件
    匿名函数 列表生成式 字典生成式 递归
    pecan API调用
    lvm磁盘分区
    PasteDeploy部署Pecan API 服务
    oslo_service服务
    python pbr 打包
    stevedore动态加载模块
    mongodb 副本集部署
    python装饰器
  • 原文地址:https://www.cnblogs.com/cold-ice/p/9166212.html
Copyright © 2011-2022 走看看