自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三次握手和四次揮手說(shuō)完了,還讓我手動(dòng)寫(xiě)個(gè)HTTP協(xié)議代碼

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
最近阿粉的同事們?cè)跍?zhǔn)備面試,其中也有收到offer的幾個(gè)不錯(cuò)的人,畢竟疫情穩(wěn)定了,而阿粉在電話面試的時(shí)候,被問(wèn)到關(guān)于HTTP協(xié)議的內(nèi)容的時(shí)候,卻顯得有點(diǎn)麻木了,為什么呢?因?yàn)樘茁诽盍?,讓阿粉猝不及防呀?/div>

最近阿粉的同事們?cè)跍?zhǔn)備面試,其中也有收到offer的幾個(gè)不錯(cuò)的人,畢竟疫情穩(wěn)定了,而阿粉在電話面試的時(shí)候,被問(wèn)到關(guān)于HTTP協(xié)議的內(nèi)容的時(shí)候,卻顯得有點(diǎn)麻木了,為什么呢?因?yàn)樘茁诽盍?,讓阿粉猝不及防呀?/p>

[[335962]]

面試官:你了解TCP/IP協(xié)議么?說(shuō)實(shí)話在阿粉聽(tīng)到這個(gè)問(wèn)題的時(shí)候,阿粉的第一想法就是,我回答了這個(gè)問(wèn)題,接下來(lái)肯定還有一個(gè)三次握手和四次揮手等著我,但是還是得回答呀,于是阿粉就開(kāi)始作答了。

阿粉開(kāi)始作答:TCP/IP協(xié)議雖然會(huì)放在一起說(shuō),但是他們其實(shí)呢是屬于兩個(gè)不同的協(xié)議。

  • IP協(xié)議:IP協(xié)議實(shí)際上是用來(lái)查找地址的,而它對(duì)應(yīng)的層級(jí)也是網(wǎng)絡(luò)層,也可以稱(chēng)之為網(wǎng)際互聯(lián)層,區(qū)別不大,叫法不同而已。
  • TCP協(xié)議:TCP協(xié)議是用來(lái)規(guī)范傳輸規(guī)則的,和IP協(xié)議是不同的,而它對(duì)應(yīng)的層級(jí)是傳輸層,而這樣的話,也就是IP去尋找地址,把所有的傳輸任務(wù)都交給TCP,而TCP這時(shí)候就相當(dāng)于一個(gè)快遞員的身份出現(xiàn)并且存在。

面試官:那你說(shuō)說(shuō)什么是三次握手,什么是四次揮手吧

1. 三次握手

大家看這個(gè)圖,圖是來(lái)自于百度搜索,而且百度上有各種各樣的圖,當(dāng)你看到圖的時(shí)候第一時(shí)間肯定是看不懂的,也就是只能通過(guò)這個(gè)畫(huà)的標(biāo)志的“線”來(lái)進(jìn)行分析,其實(shí)這僅僅只是一個(gè)方面。

那么我們就來(lái)根據(jù)圖來(lái)解析一下這個(gè)圖中都代表了什么意思,圖中存在著兩個(gè)序號(hào)和三個(gè)不同的標(biāo)志位其中有大小寫(xiě)容易混淆的呦。

序號(hào):

  • seq:sequence number 的縮寫(xiě),直譯的話,序號(hào),對(duì)沒(méi)錯(cuò),它就是序號(hào),你沒(méi)有翻譯錯(cuò),相信自己,而這個(gè)seq表示的則是自己傳遞的序號(hào),TCP在傳輸?shù)臅r(shí)候,其中的每一個(gè)字節(jié),都會(huì)有一個(gè)序號(hào),發(fā)送數(shù)據(jù)的時(shí)候,會(huì)把第一個(gè)數(shù)據(jù)的第一個(gè)序號(hào)發(fā)送給對(duì)方,就是我們所看到的第一步,而接收的這一方面,會(huì)按照這個(gè)序號(hào)來(lái)檢查是否是一個(gè)連接完整的數(shù)據(jù),如果說(shuō)你數(shù)據(jù)是完整的,那么好,我們可以繼續(xù)下一步,如果你不是完整的,那就重新傳送唄,而這樣的話也能保證數(shù)據(jù)的完整性不被破壞。
  • ack:注意,這是小寫(xiě)的ack,也就是acknoledgement number的縮寫(xiě),而他表示的是確認(rèn)號(hào),這個(gè)要和ACK(確認(rèn)位)進(jìn)行區(qū)分,接收端這時(shí)候用它來(lái)給發(fā)送端返回成功接收消息的數(shù)據(jù)信息,而這時(shí)候,它的值就是表明,我現(xiàn)在想接收下一個(gè)數(shù)據(jù)包了,而這個(gè)值就是下一個(gè)數(shù)據(jù)包的開(kāi)始的序號(hào),而這個(gè)ack所代表的的值的序號(hào)前面的數(shù)據(jù)都已經(jīng)接收成功了。
  • ACK:確認(rèn)位,確認(rèn)位來(lái)了,只有當(dāng)ACK=1的時(shí)候ack才會(huì)起到自己應(yīng)該起的作用,而在我們第一次發(fā)起請(qǐng)求的時(shí)候,因?yàn)闆](méi)有需要我們確認(rèn)的接收的數(shù)據(jù),所以這個(gè)時(shí)候的ACK就是0,而正常通信的情況下,ACK就1.
  • SYN:同步位,而同步位的作用就是用于建立連接時(shí)同步序號(hào),而剛連接的時(shí)候,說(shuō)ACK是0,那么ack就不起作用,這時(shí)候SYN就來(lái)說(shuō),你看沒(méi)我你們不行了把,要你們有何用,當(dāng)接收端接收到SYN=1的報(bào)文的時(shí)候,就會(huì)將ack設(shè)置為接收到的seq+1的值,這也是大家在看百度上提供的內(nèi)容的時(shí)候看到的,各種seq=k,ACK=k+1,這玩意就是這么來(lái)的,這時(shí)候ack的值就是根據(jù)SYN來(lái)直接設(shè)置的,這樣你才能正常的進(jìn)行傳輸,而SYN有時(shí)候會(huì)被面試官問(wèn)到為什么在前兩次握手的時(shí)候都是1呢?其實(shí)這是因?yàn)閭鬏敂?shù)據(jù)的雙方的ack都是要一個(gè)初始值的,不然你還怎么傳輸,還怎么玩。
  • FIN:終止位,這個(gè)在本圖中,并沒(méi)有完全的體現(xiàn),在四次揮手的時(shí)候就能完全的體現(xiàn)出來(lái)了。而它則是用來(lái)在數(shù)據(jù)傳輸都完成之后來(lái)釋放連接的。

那么關(guān)于這個(gè)圖,我們?cè)趺唇o面試官說(shuō)呢?

(1) 第一次握手(SYN=1, seq=x):

客戶端發(fā)送一個(gè) TCP 的 SYN 標(biāo)志位置1的包,指明客戶端打算連接的服務(wù)器的端口,以及初始序號(hào) X,保存在包頭的序列號(hào)(Sequence Number)字段里。

發(fā)送完畢后,客戶端進(jìn)入 SYN_SEND 狀態(tài)。

(2) 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):

服務(wù)器發(fā)回確認(rèn)包(ACK)應(yīng)答。即 SYN 標(biāo)志位和 ACK 標(biāo)志位均為1。服務(wù)器端選擇自己 ISN 序列號(hào),放到 Seq 域里,同時(shí)將確認(rèn)序號(hào)(Acknowledgement Number)設(shè)置為客戶的 ISN 加1,即X+1。發(fā)送完畢后,服務(wù)器端進(jìn)入 SYN_RCVD 狀態(tài)。

(3) 第三次握手(ACK=1,ACKnum=y+1)

客戶端再次發(fā)送確認(rèn)包(ACK),SYN 標(biāo)志位為0,ACK 標(biāo)志位為1,并且把服務(wù)器發(fā)來(lái) ACK 的序號(hào)字段+1,放在確定字段中發(fā)送給對(duì)方,并且在數(shù)據(jù)段放寫(xiě)ISN的+1

發(fā)送完畢后,客戶端進(jìn)入 ESTABLISHED 狀態(tài),當(dāng)服務(wù)器端接收到這個(gè)包時(shí),也進(jìn)入 ESTABLISHED 狀態(tài),TCP 握手結(jié)束。

你如果這么說(shuō),面試官有可能還會(huì)問(wèn),你這也太官方了,能不能說(shuō)說(shuō)你的理解,那么你可以用一個(gè)實(shí)際上的例子來(lái)給他說(shuō)一下,

阿粉:雞丁,嘿,我是阿粉,你聽(tīng)的到我說(shuō)話么?

雞?。撼吵成?,聽(tīng)到了,除了你我還能認(rèn)識(shí)誰(shuí)。

阿粉:你聽(tīng)的到你還不趕緊回復(fù),怪不得你沒(méi)有女朋友呢。那我們?cè)倮^續(xù)交流一下吧。

而這三次的對(duì)話過(guò)程就是通俗的三次握手,期間對(duì)話三次,以此來(lái)確定兩個(gè)方向上的數(shù)據(jù)傳輸通道是否正常。

2. 四次揮手

那么四次揮手怎么來(lái)回答呢?

(1)第一次揮手(FIN=1,seq=x)

假設(shè)客戶端想要關(guān)閉連接,客戶端發(fā)送一個(gè) FIN 標(biāo)志位置為1的包,表示自己已經(jīng)沒(méi)有數(shù)據(jù)可以發(fā)送了,但是仍然可以接受數(shù)據(jù)。

發(fā)送完畢后,客戶端進(jìn)入 FIN_WAIT_1 狀態(tài)。

(2) 第二次揮手(ACK=1,ACKnum=x+1)

服務(wù)器端確認(rèn)客戶端的 FIN 包,發(fā)送一個(gè)確認(rèn)包,表明自己接受到了客戶端關(guān)閉連接的請(qǐng)求,但還沒(méi)有準(zhǔn)備好關(guān)閉連接。

發(fā)送完畢后,服務(wù)器端進(jìn)入 CLOSE_WAIT 狀態(tài),客戶端接收到這個(gè)確認(rèn)包之后,進(jìn)入 FIN_WAIT_2 狀態(tài),等待服務(wù)器端關(guān)閉連接。

(3) 第三次揮手(FIN=1,seq=y)

服務(wù)器端準(zhǔn)備好關(guān)閉連接時(shí),向客戶端發(fā)送結(jié)束連接請(qǐng)求,F(xiàn)IN 置為1。

發(fā)送完畢后,服務(wù)器端進(jìn)入 LAST_ACK 狀態(tài),等待來(lái)自客戶端的最后一個(gè)ACK。

(4) 第四次揮手(ACK=1,ACKnum=y+1)

客戶端接收到來(lái)自服務(wù)器端的關(guān)閉請(qǐng)求,發(fā)送一個(gè)確認(rèn)包,并進(jìn)入 TIME_WAIT狀態(tài),等待可能出現(xiàn)的要求重傳的 ACK 包。

服務(wù)器端接收到這個(gè)確認(rèn)包之后,關(guān)閉連接,進(jìn)入 CLOSED 狀態(tài)。

客戶端等待了某個(gè)固定時(shí)間(兩個(gè)最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,沒(méi)有收到服務(wù)器端的 ACK ,認(rèn)為服務(wù)器端已經(jīng)正常關(guān)閉連接,于是自己也關(guān)閉連接,進(jìn)入 CLOSED 狀態(tài)。兩次后會(huì)重傳直到超時(shí)。如果多了會(huì)有大量半鏈接阻塞隊(duì)列。

那么怎么去通俗的給面試官說(shuō)呢?

阿粉:雞丁呀,我要說(shuō)的都說(shuō)完了,你還有啥事么?

雞?。耗阏f(shuō)的我都明白了,但是別斷,我還有要囑咐你的,給我找女朋友的事情。

雞丁:xxxxx,我說(shuō)完了。

阿粉,行啦,別BB了,記住了,掛了把。

如果面試官問(wèn)你的時(shí)候,你這么回答的話,既有官方的解釋?zhuān)€有本身自己的理解,那么這個(gè)問(wèn)題就已經(jīng)算是差不多了,

而面試官顯然不可能會(huì)這么放過(guò)你,肯定再給你來(lái)個(gè)雷,為啥是三次握手,而是四次揮手呢?為啥不是三次呢?

這是因?yàn)榉?wù)端在LISTEN狀態(tài)下,收到建立連接請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。而關(guān)閉連接時(shí),當(dāng)收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),己方是否現(xiàn)在關(guān)閉發(fā)送數(shù)據(jù)通道,需要上層應(yīng)用來(lái)決定,因此,己方ACK和FIN一般都會(huì)分開(kāi)發(fā)送。所以這時(shí)候揮手的時(shí)候就是四次,而不再是三次了。

那么我們?cè)趺慈ナ謱?xiě)一個(gè)HTTP協(xié)議呢?代碼送上:

  1. public class Server { 
  2.     public static void main(String[] args) throws Exception{ 
  3.         ServerSocketChannel ssc = ServerSocketChannel.open(); 
  4.         ssc.socket().bind(new InetSocketAddress(8080)); 
  5.         ssc.configureBlocking(false); 
  6.         Selector selector = Selector.open(); 
  7.         ssc.register(selector, SelectionKey.OP_ACCEPT); 
  8.         while (true){ 
  9.             if (selector.select(3000)==0){ 
  10.                 continue; 
  11.             } 
  12.             Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); 
  13.             while (keyIterator.hasNext()){ 
  14.                 SelectionKey key = keyIterator.next(); 
  15.                 new Thread(new HttpHandler(key)).run(); 
  16.                 keyIterator.remove(); 
  17.             } 
  18.         } 
  19.     } 
  20.     private static class HttpHandler implements Runnable{ 
  21.  
  22.         private int bufferSize = 1024
  23.         private String localCharset = "UTF-8"
  24.         private SelectionKey key; 
  25.         public HttpHandler(SelectionKey key){ 
  26.             this.key=key; 
  27.         } 
  28.  
  29.         public void handleAccept()throws IOException{ 
  30.             SocketChannel clientChannel = ((ServerSocketChannel)key.channel()).accept(); 
  31.             clientChannel.configureBlocking(false); 
  32.             clientChannel.register(key.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize)); 
  33.         } 
  34.  
  35.         @Override 
  36.         public void run() { 
  37.             try { 
  38.                 if (key.isAcceptable()){ 
  39.                     handleAccept(); 
  40.                 } 
  41.                 if (key.isReadable()){ 
  42.                     handleRead(); 
  43.                 } 
  44.             }catch (IOException e){ 
  45.                e.printStackTrace(); 
  46.             } 
  47.         } 
  48.  
  49.         public void handleRead() throws IOException{ 
  50.             SocketChannel sc = (SocketChannel) key.channel(); 
  51.             ByteBuffer buffer = (ByteBuffer) key.attachment(); 
  52.             buffer.clear(); 
  53.             if (sc.read(buffer)==-1){ 
  54.                 sc.close(); 
  55.             }else { 
  56.                 buffer.flip(); 
  57.                 String receiveString = Charset.forName(localCharset).newDecoder().decode(buffer).toString(); 
  58.                 String[] requestMessage = receiveString.split("\r\n"); 
  59.                 for (String s:requestMessage) { 
  60.                     System.out.println(s); 
  61.                     if (s.isEmpty()){ 
  62.                         break; 
  63.                     } 
  64.                     String[] firstLine = requestMessage[0].split(" "); 
  65.                     System.out.println(); 
  66.                     System.out.println("Method:\t"+firstLine[0]); 
  67.                     System.out.println("url:\t"+firstLine[1]); 
  68.                     System.out.println("HTTP Version:\t"+firstLine[2]); 
  69.                     System.out.println(); 
  70.  
  71.                     StringBuffer sendString = new StringBuffer(); 
  72.                     sendString.append("HTTP/1.1 200 OK\r\n"); 
  73.                     sendString.append("Content-Type:text/html;charset="+localCharset+"\r\n"); 
  74.                     sendString.append("\r\n"); 
  75.                     sendString.append("<html><head><title>顯示報(bào)文</title></head><body>"); 
  76.                     sendString.append("接受到的請(qǐng)求報(bào)文是:<br/>"); 
  77.                     for (String s1:requestMessage) { 
  78.                         sendString.append(s1+"<br/>"); 
  79.                     } 
  80.                     sendString.append("</body></html>"); 
  81.                     buffer = ByteBuffer.wrap(sendString.toString().getBytes(localCharset)); 
  82.                     sc.write(buffer); 
  83.                     sc.close(); 
  84.                 } 
  85.             } 
  86.  
  87.         } 
  88.  
  89.     } 

這是一個(gè)簡(jiǎn)單的實(shí)現(xiàn),只是實(shí)現(xiàn)思路,并不是真正的處理請(qǐng)求,而大家也要注意設(shè)置Content-Type的類(lèi)型,不然容易出問(wèn)題的,畢竟長(zhǎng)度是有限制的。

 

 

責(zé)任編輯:趙寧寧 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2017-09-25 21:27:07

TCP協(xié)議數(shù)據(jù)鏈

2015-10-13 09:42:52

TCP網(wǎng)絡(luò)協(xié)議

2021-01-29 06:11:08

TCP通信三次握手

2021-05-18 12:27:40

TCP控制協(xié)議

2023-10-24 15:22:09

TCPUDP

2019-06-12 11:26:37

TCP三次握手四次揮手

2024-01-12 08:23:11

TCPACK服務(wù)器

2023-11-01 08:04:08

WiresharkTCP協(xié)議

2015-11-09 09:58:56

2021-07-03 17:47:25

TCP控制協(xié)議

2019-02-01 09:38:16

2021-05-28 09:08:20

TCP連接序列號(hào)

2020-06-29 14:50:47

TCP狀態(tài)ACK

2023-10-28 09:07:57

TCP面試三次握手

2020-01-09 09:31:05

三次握手四次揮手 TCP

2020-02-17 10:10:43

TCP三次握手四次揮手

2023-03-07 08:38:23

三次握手四次揮手服務(wù)端

2019-01-25 09:21:30

2022-11-17 10:20:49

TCP三次握手四次揮手

2014-09-19 09:46:46

TCPIP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)