Java面試題沖刺第六天--網(wǎng)絡(luò)編程1
面試題1:說(shuō)一下TCP連接的三次握手和四次揮手吧
正經(jīng)回答:
握手:TCP連接
揮手:TCP斷開(kāi)
三次握手:
首先,三次握手的本質(zhì)是確認(rèn)通信雙方(Client端、Server端)收發(fā)數(shù)據(jù)的能力;
三次握手其實(shí)就是指:建立一個(gè)TCP連接時(shí),需要客戶(hù)端和服務(wù)器總共發(fā)送3個(gè)包,通過(guò)這三個(gè)請(qǐng)求包,來(lái)確認(rèn)雙方(Client、Server)的接收能力和發(fā)送能力是否正常,同時(shí),指定自己的初始化序列號(hào)為后面的可靠性傳送做準(zhǔn)備。實(shí)質(zhì)上就是連接服務(wù)器指定端口,建立TCP連接,并同步連接雙方的序列號(hào)和確認(rèn)號(hào),交換TCP窗口大小信息。
注:剛開(kāi)始客戶(hù)端處于 Closed 的狀態(tài),服務(wù)端處于 Listen 狀態(tài)。
三次握手(連接)流程白話(huà)文介紹:
我和女朋友養(yǎng)了一只信鴿來(lái)傳信,今天我要試一試好不好使,不好使晚上我就準(zhǔn)備吃燒烤。
第一次握手:我把信(第一封信)綁在鴿子腿上發(fā)給女朋友,如果女朋友收到了,就確定了我的發(fā)件能力和她的收件能力沒(méi)問(wèn)題;第二次握手:然后女朋友給我回信(第二封信),我如果收到了,說(shuō)明我的收件能力和她的發(fā)件能力沒(méi)問(wèn)題;第三次握手:然而此時(shí)女朋友還不知道她的發(fā)件能力和我的收件能力是否正常;因此我還要給他發(fā)(第三封信)說(shuō)明,收到后最終決定晚上去吃烤魚(yú)。信鴿:真tm累,你們手機(jī)都是假的吧。

三次握手理論流程:
第一次握手:客戶(hù)端將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個(gè)值seq=J,并將該數(shù)據(jù)包發(fā)送給服務(wù)器端,客戶(hù)端進(jìn)入SYN_SENT狀態(tài),等待服務(wù)器端確認(rèn)。第二次握手:服務(wù)器端收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道客戶(hù)端請(qǐng)求建立連接,服務(wù)器端將標(biāo)志位SYN和ACK都置為1,ack=J+1,隨機(jī)產(chǎn)生一個(gè)值seq=K,并將該數(shù)據(jù)包發(fā)送給客戶(hù)端以確認(rèn)連接請(qǐng)求,服務(wù)器端進(jìn)入SYN_RCVD狀態(tài)。第三次握手:客戶(hù)端收到確認(rèn)后,檢查ack是否為J+1,ACK是否為1,如果正確則將標(biāo)志位ACK置為1,ack=K+1,并將該數(shù)據(jù)包發(fā)送給服務(wù)器端,服務(wù)器端檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,客戶(hù)端和服務(wù)器端進(jìn)入ESTABLISHED狀態(tài),完成三次握手,隨后客戶(hù)端與服務(wù)器端之間可以開(kāi)始傳輸數(shù)據(jù)了。
四次揮手:
四次揮手即終止TCP連接,就是指斷開(kāi)一個(gè)TCP連接時(shí),需要客戶(hù)端和服務(wù)端總共發(fā)送4個(gè)包以確認(rèn)連接的斷開(kāi)。在socket編程中,這一過(guò)程由客戶(hù)端或服務(wù)端任一方執(zhí)行close來(lái)觸發(fā)。
由于TCP連接是全雙工的,因此,每個(gè)方向都必須要單獨(dú)進(jìn)行關(guān)閉,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后,發(fā)送一個(gè)FIN來(lái)終止這一方向的連接,收到一個(gè)FIN只是意味著這一方向上沒(méi)有數(shù)據(jù)流動(dòng)了,即不會(huì)再收到數(shù)據(jù)了,但是在這個(gè)TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動(dòng)關(guān)閉,而另一方則執(zhí)行被動(dòng)關(guān)閉。

四次揮手理論流程
中斷連接端可以是客戶(hù)端,也可以是服務(wù)器端。
第一次揮手:客戶(hù)端發(fā)送一個(gè)FIN=M,用來(lái)關(guān)閉客戶(hù)端到服務(wù)器端的數(shù)據(jù)傳送,客戶(hù)端進(jìn)入FIN_WAIT_1狀態(tài)。意思是說(shuō)"我客戶(hù)端沒(méi)有數(shù)據(jù)要發(fā)給你了",但是如果你服務(wù)器端還有數(shù)據(jù)沒(méi)有發(fā)送完成,則不必急著關(guān)閉連接,可以繼續(xù)發(fā)送數(shù)據(jù)。
第二次揮手:服務(wù)器端收到FIN后,先發(fā)送ack=M+1,告訴客戶(hù)端,你的請(qǐng)求我收到了,但是我還沒(méi)準(zhǔn)備好,請(qǐng)繼續(xù)你等我的消息。這個(gè)時(shí)候客戶(hù)端就進(jìn)入FIN_WAIT_2 狀態(tài),繼續(xù)等待服務(wù)器端的FIN報(bào)文。
第三次揮手:當(dāng)服務(wù)器端確定數(shù)據(jù)已發(fā)送完成,則向客戶(hù)端發(fā)送FIN=N報(bào)文,告訴客戶(hù)端,好了,我這邊數(shù)據(jù)發(fā)完了,準(zhǔn)備好關(guān)閉連接了。服務(wù)器端進(jìn)入LAST_ACK狀態(tài)。
第四次揮手:客戶(hù)端收到FIN=N報(bào)文后,就知道可以關(guān)閉連接了,但是他還是不相信網(wǎng)絡(luò),怕服務(wù)器端不知道要關(guān)閉,所以發(fā)送ack=N+1后進(jìn)入TIME_WAIT狀態(tài),如果Server端沒(méi)有收到ACK則可以重傳。服務(wù)器端收到ACK后,就知道可以斷開(kāi)連接了。客戶(hù)端等待了2MSL后依然沒(méi)有收到回復(fù),則證明服務(wù)器端已正常關(guān)閉,那好,我客戶(hù)端也可以關(guān)閉連接了。最終完成了四次握手。
深入追問(wèn):
追問(wèn)1:為什么連接的時(shí)候是三次握手,關(guān)閉的時(shí)候卻是四次握手?
因?yàn)楫?dāng)Server端收到Client端的SYN連接請(qǐng)求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文。其中ACK報(bào)文是用來(lái)應(yīng)答的,SYN報(bào)文是用來(lái)同步的。但是關(guān)閉連接時(shí),當(dāng)Server端收到FIN報(bào)文時(shí),很可能并不會(huì)立即關(guān)閉SOCKET,所以只能先回復(fù)一個(gè)ACK報(bào)文,告訴Client端,“你發(fā)的FIN報(bào)文我收到了”。只有等到我Server端所有的報(bào)文都發(fā)送完了,我才能發(fā)送FIN報(bào)文,因此不能一起發(fā)送。故需要四步握手。
追問(wèn)2:如果已經(jīng)建立了連接,但是客戶(hù)端突然出現(xiàn)故障了怎么辦?
TCP還設(shè)有一個(gè)保活計(jì)時(shí)器,顯然,客戶(hù)端如果出現(xiàn)故障,服務(wù)器不能一直等下去,白白浪費(fèi)資源。服務(wù)器每收到一次客戶(hù)端的請(qǐng)求后都會(huì)重新復(fù)位這個(gè)計(jì)時(shí)器,時(shí)間通常是設(shè)置為2小時(shí),若兩小時(shí)還沒(méi)有收到客戶(hù)端的任何數(shù)據(jù),服務(wù)器就會(huì)發(fā)送一個(gè)探測(cè)報(bào)文段,以后每隔75秒鐘發(fā)送一次。
若一連發(fā)送10個(gè)探測(cè)報(bào)文仍然沒(méi)反應(yīng),服務(wù)器就認(rèn)為客戶(hù)端出了故障,接著就關(guān)閉連接。
面試題2:常見(jiàn)的HTTP狀態(tài)碼有哪些?
正經(jīng)回答:
HTTP狀態(tài)碼表示客戶(hù)端HTTP請(qǐng)求的返回結(jié)果、標(biāo)識(shí)服務(wù)器處理是否正常、表明請(qǐng)求出現(xiàn)的錯(cuò)誤等。
狀態(tài)碼的類(lèi)別:
| 狀態(tài)碼 | 原因 |
|---|---|
| 1XX | Informational(信息性狀態(tài)碼) 接受的請(qǐng)求正在處理 |
| 2XX | Success(成功狀態(tài)碼) 請(qǐng)求正常處理完畢 |
| 3XX | Redirection(重定向狀態(tài)碼) 需要進(jìn)行附加操作以完成請(qǐng)求 |
| 4XX | Client Error(客戶(hù)端錯(cuò)誤狀態(tài)碼) 服務(wù)器無(wú)法處理請(qǐng)求 |
| 5XX | Server Error(服務(wù)器錯(cuò)誤狀態(tài)碼) 服務(wù)器處理請(qǐng)求出錯(cuò) |
| 狀態(tài)碼 | 原因 |
|---|---|
| 2XX | 成功(這系列表明請(qǐng)求被正常處理了) |
| 200 | OK,表示從客戶(hù)端發(fā)來(lái)的請(qǐng)求在服務(wù)器端被正確處理 |
| 204 | No content,表示請(qǐng)求成功,但響應(yīng)報(bào)文不含實(shí)體的主體部分 |
| 206 | Partial Content,進(jìn)行范圍請(qǐng)求成功 |
| 狀態(tài)碼 | 原因 |
|---|---|
| 3XX | 重定向(表明瀏覽器要執(zhí)行特殊處理) |
| 301 | moved permanently,永久性重定向,表示資源已被分配了新的 URL |
| 302 | found,臨時(shí)性重定向,表示資源臨時(shí)被分配了新的 URL |
| 303 | see other,表示資源存在著另一個(gè) URL,應(yīng)使用 GET 方法獲取資源 |
| 304 | not modified,表示服務(wù)器允許訪(fǎng)問(wèn)資源,但請(qǐng)求未滿(mǎn)足條件的情況(與重定向無(wú)關(guān)) |
| 307 | temporary redirect,臨時(shí)重定向,和302含義類(lèi)似,但是期望客戶(hù)端保持請(qǐng)求方法不變向新的地址發(fā)出請(qǐng)求 |
| 狀態(tài)碼 | 原因 |
|---|---|
| 4XX | 客戶(hù)端錯(cuò)誤 |
| 400 | bad request,請(qǐng)求報(bào)文存在語(yǔ)法錯(cuò)誤 |
| 401 | unauthorized,表示發(fā)送的請(qǐng)求需要有通過(guò) HTTP 認(rèn)證的認(rèn)證信息 |
| 403 | forbidden,表示對(duì)請(qǐng)求資源的訪(fǎng)問(wèn)被服務(wù)器拒絕,可在實(shí)體主體部分返回原因描述 |
| 404 | not found,表示在服務(wù)器上沒(méi)有找到請(qǐng)求的資源 |
| 狀態(tài)碼 | 原因 |
|---|---|
| 5XX | 服務(wù)器錯(cuò)誤 |
| 500 | internal sever error,表示服務(wù)器端在執(zhí)行請(qǐng)求時(shí)發(fā)生了錯(cuò)誤 |
| 501 | Not Implemented,表示服務(wù)器不支持當(dāng)前請(qǐng)求所需要的某個(gè)功能 |
| 503 | service unavailable,表明服務(wù)器暫時(shí)處于超負(fù)載或正在停機(jī)維護(hù),無(wú)法處理請(qǐng)求 |
面試題3:先說(shuō)說(shuō)GET和POST請(qǐng)求有哪些區(qū)別吧?
正經(jīng)回答:
GET請(qǐng)求在URL中傳送的參數(shù)是有長(zhǎng)度限制的,而POST沒(méi)有。
GET比POST更不安全,因?yàn)閰?shù)直接暴露在URL上,所以不能用來(lái)傳遞敏感信息。而POST數(shù)據(jù)不會(huì)顯示在URL中。是放在Request body中。
對(duì)參數(shù)的數(shù)據(jù)類(lèi)型,GET只接受ASCII字符,而POST沒(méi)有限制。
GET請(qǐng)求參數(shù)會(huì)被完整保留在瀏覽器歷史記錄里;相反,POST請(qǐng)求參數(shù)也不會(huì)被瀏覽器保留。
GET請(qǐng)求只能進(jìn)行url編碼(application/x-www-form-urlencoded),而POST支持多種編碼方式。
GET請(qǐng)求會(huì)被瀏覽器主動(dòng)緩存,而POST不會(huì),除非手動(dòng)設(shè)置。
GET在瀏覽器回退時(shí)是無(wú)害的,而POST會(huì)再次提交請(qǐng)求。
深入追問(wèn):
追問(wèn)1:那Get請(qǐng)求有Request body么?如果有的話(huà)參數(shù)可以像Post請(qǐng)求一樣放在里面么?
其實(shí)吧,GET和POST在本質(zhì)上沒(méi)有區(qū)別,都是HTTP協(xié)議中的兩種發(fā)送請(qǐng)求的方法。而HTTP呢,是基于TCP/IP的關(guān)于數(shù)據(jù)如何在萬(wàn)維網(wǎng)中如何通信的協(xié)議。
萬(wàn)維網(wǎng):簡(jiǎn)稱(chēng)WWW,是World Wide Web的簡(jiǎn)稱(chēng),也稱(chēng)為Web、3W等
HTTP的底層是TCP/IP。所以GET和POST的底層也是TCP/IP,也就是說(shuō),GET/POST都是TCP鏈接。
GET和POST能做的事情是一樣一樣的。你要給GET加上request body,給POST帶上url參數(shù),技術(shù)上是完全行的通的。
- 舉個(gè)例子吧:
TCP就像汽車(chē),我們用TCP來(lái)運(yùn)輸數(shù)據(jù),它很可靠,從來(lái)不會(huì)發(fā)生丟件少件的現(xiàn)象。
但是如果路上跑的全是看起來(lái)一模一樣的汽車(chē),那這個(gè)世界看起來(lái)是一團(tuán)混亂,送急件的汽車(chē)可能被前面滿(mǎn)載貨物的汽車(chē)攔堵在路上,整個(gè)交通系統(tǒng)一定會(huì)癱瘓。

為了避免這種情況發(fā)生,交通規(guī)則HTTP誕生了。HTTP給汽車(chē)運(yùn)輸設(shè)定了好幾個(gè)服務(wù)類(lèi)別,包括GET, POST, PUT等等,
HTTP規(guī)定,當(dāng)執(zhí)行GET請(qǐng)求的時(shí)候,要給汽車(chē)貼上GET的標(biāo)簽(設(shè)置method為GET),而且要求把傳送的數(shù)據(jù)放在車(chē)頂上(url中)以方便記錄。
如果是POST請(qǐng)求,就要在車(chē)上貼上POST的標(biāo)簽,并把貨物放在車(chē)廂里(request body中)。
當(dāng)然,你也可以在用GET的時(shí)往車(chē)廂內(nèi)偷偷藏點(diǎn)貨物,但這并不不光彩;也可以在POST的時(shí)候在車(chē)頂上也放一些數(shù)據(jù),也會(huì)讓人覺(jué)得傻乎乎的。

HTTP只是個(gè)行為準(zhǔn)則,而GET和POST本質(zhì)上就是TCP鏈接,并無(wú)差別。但是由于HTTP的規(guī)定和瀏覽器/服務(wù)器的限制,導(dǎo)致他們?cè)趹?yīng)用過(guò)程中體現(xiàn)出一些不同。
追問(wèn)2:那你剛才說(shuō)的URL中傳送參數(shù)的長(zhǎng)度限制在Get和Post中都是怎么樣的呢?
其實(shí)在Web中啊,還有另一個(gè)重要的角色:運(yùn)輸公司。
不同的瀏覽器Client端(發(fā)起http請(qǐng)求)和服務(wù)器server端(接受http請(qǐng)求)就是不同的運(yùn)輸公司。
雖然理論上,你可以在車(chē)頂上無(wú)限的堆貨物(url中無(wú)限加參數(shù))。但是運(yùn)輸公司可不傻,裝貨和卸貨也是有很大成本的,他們會(huì)限制單次運(yùn)輸量來(lái)控制風(fēng)險(xiǎn),數(shù)據(jù)量太大對(duì)瀏覽器和服務(wù)器都是很大負(fù)擔(dān)。
業(yè)界不成文的規(guī)定是:(大多數(shù))瀏覽器通常都會(huì)限制url長(zhǎng)度在2K個(gè)字節(jié),而(大多數(shù))服務(wù)器最多處理64K大小的url。
超過(guò)的部分,恕不處理。如果你用GET服務(wù),在request body偷偷藏了數(shù)據(jù),不同服務(wù)器的處理方式也是不同的,有些服務(wù)器會(huì)幫你卸貨,讀出數(shù)據(jù),有些服務(wù)器直接忽略。
所以,雖然GET可以帶request body,卻不能保證一定能被接收到。

我之前處理過(guò)一個(gè)bug,用戶(hù)反應(yīng)查詢(xún)沒(méi)有響應(yīng),同事查了日志后才發(fā)現(xiàn)有幾個(gè)參數(shù)都是undefined,很奇怪,最后發(fā)現(xiàn)原來(lái)是因?yàn)镚et請(qǐng)求第一個(gè)查詢(xún)參數(shù)太長(zhǎng)了,導(dǎo)致URL后面的部分服務(wù)器無(wú)法接收 ,后來(lái)把請(qǐng)求改成post,將參數(shù)放在request body后就可以了。
追問(wèn)3:那么你知道Get、Post請(qǐng)求發(fā)送的數(shù)據(jù)包有什么不同嗎?
嗯嗯,是這樣的,GET請(qǐng)求時(shí)產(chǎn)生一個(gè)TCP數(shù)據(jù)包;POST請(qǐng)求時(shí)產(chǎn)生兩個(gè)TCP數(shù)據(jù)包。
- GET:瀏覽器會(huì)把http header和data一并發(fā)送出去,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù));
- POST:瀏覽器先發(fā)送header,服務(wù)器響應(yīng)100 continue,瀏覽器再發(fā)送data,服務(wù)器響應(yīng)200 OK(返回?cái)?shù)據(jù))。
就像是GET只需要汽車(chē)跑一趟就把貨送到了,而POST得跑兩趟,第一趟,先去和服務(wù)器打個(gè)招呼“老鐵,我等下要送一批貨來(lái),你們準(zhǔn)備接收一下哈”,然后再回頭把貨送過(guò)去。
因?yàn)镻OST需要兩步,理論上時(shí)間上消耗的要多一點(diǎn),看起來(lái)GET比POST更有效。但并不是,后來(lái)發(fā)現(xiàn)原來(lái)是個(gè)坑。在我看來(lái):
1.GET與POST都有自己的語(yǔ)義,不能隨便混用。
2.據(jù)研究,在網(wǎng)絡(luò)環(huán)境好的情況下,發(fā)一次包的時(shí)間和發(fā)兩次包的時(shí)間差別基本可以無(wú)視。而在網(wǎng)絡(luò)環(huán)境差的情況下,兩次包的TCP在驗(yàn)證數(shù)據(jù)包完整性上,有非常大的優(yōu)點(diǎn)。
3.并不是所有瀏覽器都會(huì)在POST中發(fā)送兩次包,F(xiàn)irefox就只發(fā)送一次。我去年用Chrome瀏覽器測(cè)試發(fā)現(xiàn)也是只發(fā)送一次,所以我認(rèn)為Get、POST性能差可以人為忽略。
總結(jié)
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
在java poi導(dǎo)入Excel通用工具類(lèi)示例詳解
這篇文章主要給大家介紹了關(guān)于在java poi導(dǎo)入Excel通用工具類(lèi)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09
java 正則表達(dá)式獲取兩個(gè)字符中間的字符串方法
今天小編就為大家分享一篇java 正則表達(dá)式獲取兩個(gè)字符中間的字符串方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
總結(jié)一下Java回調(diào)機(jī)制的相關(guān)知識(shí)
今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java回調(diào)機(jī)制展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
SpringBoot從0到1整合銀聯(lián)無(wú)跳轉(zhuǎn)支付功能附源碼
這篇文章主要介紹了SpringBoot從0到1整合銀聯(lián)無(wú)跳轉(zhuǎn)功能支付附源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
java實(shí)現(xiàn)即賦值也判斷的寫(xiě)法示例
這篇文章主要為大家介紹了java實(shí)現(xiàn)即賦值也判斷的寫(xiě)法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
SpringBoot+Redission實(shí)現(xiàn)排行榜功能的示例代碼
這篇文章主要介紹了基于SpringBoot+Redission實(shí)現(xiàn)排行榜功能,實(shí)現(xiàn)一個(gè)排行榜,要求按照分?jǐn)?shù)和達(dá)成這個(gè)分?jǐn)?shù)的時(shí)間排序,即相同分?jǐn)?shù)下,時(shí)間早的在上面,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05
Java內(nèi)部類(lèi)及其特點(diǎn)的講解
今天小編就為大家分享一篇關(guān)于Java內(nèi)部類(lèi)及其特點(diǎn)的講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
解決SpringBoot打成jar運(yùn)行后無(wú)法讀取resources里的文件問(wèn)題
這篇文章主要介紹了解決SpringBoot打成jar運(yùn)行后無(wú)法讀取resources里的文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
mybatis-plus getOne和邏輯刪除問(wèn)題詳解
這篇文章主要介紹了mybatis-plus getOne和邏輯刪除,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Java ExecutorServic線(xiàn)程池異步實(shí)現(xiàn)流程
這篇文章主要介紹了Java ExecutorServic線(xiàn)程池異步實(shí)現(xiàn)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12

