[面試] 4. 網絡協議相關

本文章收錄於:後端工程師面試題目總結(提供參考答案)

目錄

1. GET和POST區別是什麼,HTTP狀態碼瞭解哪些?

2.  Session和Cookie的區別?Session如何管理?

3. HTTPS的解釋?爲什麼要有HTTPS?

4. 簡述HTTPS密鑰協商過程?

5. 簡述跨域產生背景以及常見解決方案?

6. 解釋一下socket長連接?和Websocket協議的區別?

7. 談談select和poll和epoll

8.  TCP與UDP區別;簡述三次握手和四次揮手過程

9. TIME_WAIT過多的原因?如何解決?

10. CLOSE_WAIT什麼時候出現?什麼場景出現大量CLOSE_WAIT?如何解決?

11. 一個http請求由哪幾部分組成?

12. 談談HTTP長連接和短連接

13. HTTP長連接與TCP長連接的關係


1. GET和POST區別是什麼,HTTP狀態碼瞭解哪些?


    相同:兩者都是基於TCP協議工作的。
    區別:
    1.1 GET請求一般會被瀏覽器主動cache,POST不會
        (這點很重要,cache刷新頁面瀏覽器不會再請求服務器,如果設置了max-age的話,減輕服務器負載,提升用戶體驗)
    1.2 GET請求中傳送的參數是有長度限制的(協議規範沒有,各個瀏覽器有,IE最短是2083bytes),
        POST沒有(但受服務器處理能力影響)。程序內部調用則URL長度不受限制。
    1.3 GET參數是明文保存在URL中,POST參數保存在body中。


2.  Session和Cookie的區別?Session如何管理?


    相同:兩者都是用來跟蹤瀏覽器用戶身份的會話方式
    區別:

  •     2.1 cookie保存在客戶端,session在服務器端
  •     2.2 保存在客戶端就意味着cookie可能被分析並用來實施cookie欺騙,而session不會(也只是相對安全)
  •     2.3 session存在服務器端就意味着需要消耗服務器性能。
  •     2.4 cookie的大小會被瀏覽器限制,一般是4KB(包括key-value),session沒有理論限制。

    小結:cookie和session兩者各有優缺點,實際使用中可將兩者結合。

  • session管理:

        第一種:保存在服務端,由服務端將所有用戶的會話信息保存在內存中,然後返回一個唯一對應的sessionid給瀏覽器,瀏覽器將其保存在cookie中,下次請求發送cookie即可,如果服務器是集羣部署或者分佈式,可以用redis來存儲session。
        第二種:cookie-based,即將用戶會話信息以cookie形式保存在瀏覽器,這種方式服務器無壓力。只是cookie大小受制於瀏覽器。
        第三種:token-based,服務器將第一次登錄傳入的賬戶密碼做了驗證後,將時間戳+賬戶ID通過對稱加密後得到的子串發給瀏覽器作爲token,下次把明文賬戶ID和token放在header或者URL中帶過來就行了,服務端解密token驗證賬戶ID是否正確以及時間戳是否過期即可。


3. HTTPS的解釋?爲什麼要有HTTPS?


    和HTTP一樣也屬於應用層,基於TCP協議,區別是:
    HTTP默認工作在80端口;後者是443端口
    HTTPS在HTTP基礎上加了一個加密的身份驗證層,即SSL。
    全稱是:超文本傳輸安全協議。
    爲什麼要有HTTPS(主要作用):
        1. 建立一個信息安全通道,保證數據傳輸安全(HTTP是明文傳輸數據)。
        2. 確認網站真實性,使用HTTPS必須註冊有效證書,證書包含註冊人相關信息。

 

4. 簡述HTTPS密鑰協商過程?(參考文章:https://www.cnblogs.com/binyue/p/4500578.html)

  •     4.1 客戶端瀏覽器先將自己支持的一套加密規則發給網站服務器
  •     4.2 服務器從中選出一套加密算法與HASH算法,並加上證書發回給瀏覽器。     

        證書中包含網站地址、加密公鑰、證書CA等信息。

  •     4.3 然後瀏覽器做以下驗證:

        1. 驗證CA是否合法,以及證書中的網站地址是否就是正在訪問的地址,若都正常則再驗證證書是否過期,
            若過期則頁面會提示用戶,用戶自己選擇是否信任該證書。
        2. 若證書有效或用戶選擇信任證書,瀏覽器會生成一串隨機密碼(這個很關鍵),並用公鑰加密。
        3. 然後用之前約定好的HASH算法對握手消息進行HASH後得到一個hash值,
            再用隨機密碼對明文握手消息【對稱加密】得到一個加密的握手消息。
        將上面生成的:
            a. 公鑰加密過的隨機密碼
            b. 握手消息的hash值
            c. 握手消息的對稱加密值
        發送給服務器。

  •     4.4 服務器收到一堆信息後做如下操作:

        1. 用自己的私鑰解密取出隨機密碼
        2. 用隨機密碼解密握手消息
        3. 用協商好的hash算法對握手消息進行hash再匹配傳過來的hash值是否一致
        4. 都OK,則用隨機密碼對稱加密一個自己的握手消息和這個握手消息的hash值發給瀏覽器
        

  •     4.5 瀏覽器用隨機密碼提取握手消息,並計算hash值是否正確。

    * 至此密鑰協商結束,隨機密碼就是後續的對稱加密解密的密鑰。
    HTTPS一般使用的加密與HASH算法如下:
        非對稱加密算法:RSA,DSA/DSS
        對稱加密算法:AES,RC4,3DES
        HASH算法:MD5,SHA1,SHA256
        
    小結:HTTPS的通信過程分兩階段:密鑰協商階段+數據傳輸階段,前者使用非對稱加密,後者使用對稱加密。
            每個客戶端協商的密鑰不同,服務器將維護多個密鑰
    爲什麼後面要用相比不太安全的的對稱加密?
    答:因爲相較於非對稱,對稱加密不需要過多數學計算,更快更高效。

備註:證書申請之後,自己會有兩個證書相關文件,一個是包含證書公鑰、綁定域名、CA相關信息的文件,另一個是證書私鑰,用來在HTTPS祕鑰協商過程中使用的,證書文件的後綴可以是pem/cer/crt等,私鑰文件後綴一般是pem,可參考此鏈接下文部分說明。

擴展:SSL證書申請過程

5. 簡述跨域產生背景以及常見解決方案?

 

  •     5.1 產生背景

        實際開發工作中經常會有跨域的情況發生,比如
        1. 一個公司一般都有多個項目,自然也會有多個子域名,項目之間會有相互調用對方的功能/資源的需求,
            可以節省許多不必要的開發工作。
        2. 現在需要項目都是前後端分離,前端調用後端資源就是跨域請求。

  •     5.2 解決方案

        a. CORS(跨域資源共享)
            1. 需要瀏覽器支持,不過現在的瀏覽器幾乎都支持。
            2. 這種方案會使得瀏覽器多出一次附加的預檢請求(針對非簡單請求)
            一般在nginx中進行配置,之後就不用再app中配置。
            在nginx的enable-cors.conf文件進行header配置,可以指定允許的跨域源URL。然後在nginx.conf 
            中include [enable-cors.conf]這個文件。
            擴展:服務器返回的“Access-Control-Max-Age” 是什麼作用?
                答:用來指定本次預檢的有效期,單位秒。有效期類同一個URL無需再發預檢請求。
        b. jsonp跨域(僅支持GET方式)


        
6. 解釋一下socket長連接?和Websocket協議的區別?


   Socket長連接其實指的就是TCP長連接的(UDP沒有連接)
    指的是一個TCP連接上可以連續發送多個數據報,在連接空閒時,通過心跳包(keep-alive)維持,兩端都有超時機制。
    優勢:降低資源消耗,提高數據傳輸速率。(連接的建立和銷燬比較浪費時間和資源)
    使用場景:訪問量(連接數)較少,通訊頻繁的情況,如聊天室、數據庫連接。
    和Websocket協議的區別?
    socket長連接是允許一個TCP連接存活更久,更靠近底層,但消息邊界需要自己處理,而且是單工的,即客戶方是固定的。
    websocket則是一種全新的協議,它基於http協議建立一個長久的連接,不需要處理消息邊界問題,而且是一個全雙工的模式;
    不需要心跳來維持,但是實際情況中可能會因爲網絡質量差或nginx訪問超時設置等原因導致連接斷開,所以一般都會
    在客戶端設置心跳機制(30s一次)。


    
7. 談談select和poll和epoll


    select:時間複雜度是O(n)
            是對所有scoket句柄(fd)進行定時輪詢,發現有準備就緒的fd,就對其操作。
            fd越多,輪詢時間越長,當有準備就緒的fd是排在最後時,效率很低。
            
    poll:時間複雜度是O(n)
            本質上和select無差別,都是輪詢機制,只是它沒有最大fd數量限制。
    epoll:時間複雜度是O(1)
            這是一種事件驅動的機制,epoll能直接知道哪個fd狀態變化,然後直接調用對應回調函數。
            這是一種非常高效率的機制,fd數量增加也不會影響其效率,上面兩種會直接受到影響。

 

8.  TCP與UDP區別;簡述三次握手和四次揮手過程


    相同:傳輸層協議,用於報文傳輸
    不同:TCP比UDP可靠,是面向連接的,擁有三次握手和四次揮手、以及流量管理、擁塞控制等機制來保證傳輸過程可靠,安全。
          而UDP傳輸過程簡單,快速高效,且開銷小,因爲沒有建立連接的過程,報文頭部僅8字節,TCP頭部20字節以及40字節可選項。
          但是它沒有ACK和序列號機制,無法解決報文丟失和順序錯亂問題。
          
          TCP只能點對點(P2P),UDP可以一對一,一對多,多對多(P2MP)。
    

  •     三次握手:

        1. client發送SYN(seq=x)報文 => server(client狀態變爲SYN_SENT)
        2. server發送ACK(seq=x+1)以及SYN(seq=y)報文 =>client (server狀態變爲SYN_RECV)
        3. client發送ACK(seq=y+1) => server (client變爲ESTABLISHED,服務器收到後也變爲ESTABLISHED)   

  •     四次揮手:

        1. client發送FIN(seq=x) =>server (client變爲FIN_WAIT_1)
        2. server先回復ACK(seq=x+1) => client (server只要收到FIN報文就會變爲CLOSE_WAIT, client變爲FIN_WAIT_2)
        3. server發送完剩餘的數據報文後,再發送FIN(seq=y) =>client (server變爲LAST_CHECK)
        4. client發送ACK(seq=y+1) => server (client變爲TIME_WAIT)
        server收到ACK後直接就關閉closed狀態,但client要等2MSL(最大報文生存時間)纔會變爲closed。
        client的狀態轉變順序:established-->fin_wait_1->fin_wait_2->time_wait->closed
        server的狀態轉變順序: established-->close_wait->last_ack->closed 

 

9. TIME_WAIT過多的原因?如何解決?

注意:TIME_WAIT只出現在“客戶端”,這個“客戶端”指的是先發FIN報文的一方。那麼這裏出現過多的TIME_WAIT的一方肯定不是我們常見的那個客戶端,而是後臺服務器,後臺主動斷開連接,那麼它自然就成了所謂的“客戶端”。
    這種情況一般出現在服務器短時間內處理了大量TCP請求,主動關閉連接時就會有這個狀態,這個狀態將持續可能1-4分鐘。
    在這些連接狀態變爲CLOSED前其佔用端口都不能再使用,即無法建立新的連接。
    修改內核配置/etc/sysctl.conf:
    net.ipv4.tcp_syncookies = 1 表示開啓SYN Cookies。當出現SYN等待隊列溢出時,啓用cookies來處理,
                                可防範少量SYN攻擊,默認爲0,表示關閉;
    net.ipv4.tcp_tw_reuse = 1 表示開啓重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認爲0,表示關閉;
    net.ipv4.tcp_tw_recycle = 1 表示開啓TCP連接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉。
    net.ipv4.tcp_fin_timeout 表示如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間。
    net.ipv4.tcp_max_tw_buckets = 10000 表示系統同時保持TIME_WAIT套接字的最大數量
    使之生效: /sbin/sysctl -p 

 

10. CLOSE_WAIT什麼時候出現?什麼場景出現大量CLOSE_WAIT?如何解決?


    CLOSE_WAIT是被動關閉方收到FIN報文後的狀態,然後等待自身數據傳輸完成後,就會變爲LAST_ACK狀態。
    什麼場景出現大量CLOSE_WAIT:
        主動關閉方發送了FIN報文,但被動關閉方收到之後沒有響應(一般是因爲上層服務沒有及時調用socket的close方法,
        原因可能是程序死鎖導致的耗時過久),主動關閉方會在自己設置的tcp連接超時時間結束後關閉socket,而被動關閉方則一直保持CLOSE_WAIT,直至超時。(默認CLOSE_WAIT會保持2小時)
    解決:檢查服務端(出現CLOSE_WAIT)的機器本身對應進程的問題。
        如果程序本身沒有問題,則修改內核參數:
        net.ipv4.tcp_keepalive_time = 1800  TCP連接的超時時間,默認7200s,適當減小這個值
        net.ipv4.tcp_keepalive_probes = 3   超時後探測包發送的次數,達到上面這個時間後以及探測包發送次數上限後,斷開連接。
        net.ipv4.tcp_keepalive_intvl = 15   超時後探測包發送的時間間隔


        
11. 一個http請求由哪幾部分組成?


    由請求方法、請求頭、空行、請求體組成。

 

12. 談談HTTP長連接和短連接


    短連接就是一個http請求完成後即斷開TCP連接,下次來仍然需要建立連接。
    
    長連接是一個http請求完成後仍然保持TCP連接,同域名下依然可以用這個通道傳輸數據。
    HTTP1.1 默認保持長連接,HTTP1.0就需要設置 Connection: Keep-alive。

    設置Connection: close 則不使用長連接。
    通過Keep-Alive : timeout-20(或max=20) 查看長連接最大空閒時間/單個長連接最大請求次數。
    當然服務端有可能不會告訴客戶端連接保持時間,這不影響什麼,服務端最後會用四次揮手來關閉連接,客戶端
    會知道該連接不可用然後重新建立連接。
    
    長連接通過兩種方式來識別單次傳輸結束:
        1. 通過Content-Length字段
        2. 若數據是動態生成,沒有Content-Length,那就是分塊傳輸(chunked),通過header中的Transfer-Encoding:chunk設置, 這時候通過最後一個長度爲0的chunk來判斷該次傳輸結束。

 

13. HTTP長連接與TCP長連接的關係


    前者處於應用層協議機制,後者是傳輸層機制,前者實現基於後者。
    HTTP中的keep-alive表示客戶端希望服務器持久化本次TCP連接通道;
    TCP中的keep-alive是TCP協議的長連接機制,通過配置keep-alive超時時間來設置TCP連接的最大空閒時間,
    TCP連接空閒超時後,未關閉的socket會定時發送探測包來檢測通道是否正常,若發送N次都未收到迴應,則認爲對方已關閉,然後關閉自己的socket。
    

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