大家好,我是小林。
這次跟大家分享一位同學面騰訊后端開發(fā)的面經(jīng),一步一步深挖計算機基礎的內(nèi)容,問的問題很多,光面試時常長達 1 個小時多,再加上寫算法 20 分鐘,面試的強度還是挺大的。
雖然面試強度是比較大了一點,但是整體面下來,同學反饋還是很有收獲的,也算是對自己沒掌握的內(nèi)容進行查漏補缺的過程。
計算機網(wǎng)絡
網(wǎng)絡七層模型分別是什么?
為了使得多種設備能通過網(wǎng)絡相互通信,和為了解決各種不同設備在網(wǎng)絡互聯(lián)中的兼容性問題,國際標準化組織制定了開放式系統(tǒng)互聯(lián)通信參考模型(Open System Interconnection Reference Model),也就是 OSI 網(wǎng)絡模型,該模型主要有 7 層,分別是應用層、表示層、會話層、傳輸層、網(wǎng)絡層、數(shù)據(jù)鏈路層以及物理層。
img-
應用層:應用層最接近終端用戶。大多數(shù)應用程序都位于這一層。我們從后端服務器請求數(shù)據(jù),無需了解數(shù)據(jù)傳輸?shù)木唧w細節(jié)。這一層的協(xié)議包括 HTTP、SMTP、FTP、DNS 等。
-
表示層:這一層處理數(shù)據(jù)編碼、加密和壓縮,為應用層準備數(shù)據(jù)。例如,HTTPS 利用 TLS(Transport Layer Security)實現(xiàn)客戶端與服務器之間的安全通信。
-
會話層:該層用于打開和關閉兩個設備之間的通信。如果數(shù)據(jù)量較大,會話層就會設置檢查點,避免從頭開始重新發(fā)送。
-
傳輸層:該層處理兩個設備之間的端到端的通信。它在發(fā)送方將數(shù)據(jù)分解成段,然后在接收方重新組裝。這一層有流量控制,以防止擁塞。這一層的主要協(xié)議是 TCP 和 UDP。
-
網(wǎng)絡層:這一層實現(xiàn)不同網(wǎng)絡之間的數(shù)據(jù)傳輸。它進一步將網(wǎng)段或數(shù)據(jù)報分解成更小的數(shù)據(jù)包,并使用 IP 地址找到通往最終目的地的最佳路由。
-
數(shù)據(jù)鏈路層:這一層允許在同一網(wǎng)絡的設備之間傳輸數(shù)據(jù)。數(shù)據(jù)包被分解成幀,這些幀被限制在局域網(wǎng)內(nèi)。
-
物理層:這一層通過電纜和交換機發(fā)送比特流,因此與設備之間的物理連接密切相關。與 OSI 模型相比,TCP/IP 模型只有 4 層。在討論網(wǎng)絡協(xié)議的層次時,必須明確上下文。
TCP和UDP的應用場景是哪些?
TCP適用:網(wǎng)頁、電子郵件、遠程登錄連接、文件傳輸
UDP適用:語音通話,多播通信,DNS解析
TCP如何實現(xiàn)可靠傳輸?
面向連接、同步序列號、校驗和、流量控制和擁塞控制。
- 序列號與確認機制:TCP將每個數(shù)據(jù)包分配一個唯一的序列號,并且接收方會發(fā)送確認消息來確認已經(jīng)接收到的數(shù)據(jù)。發(fā)送方會根據(jù)接收到的確認消息判斷是否需要重新發(fā)送丟失的數(shù)據(jù)包。
- 數(shù)據(jù)校驗和:TCP使用校驗和來驗證數(shù)據(jù)在傳輸過程中是否發(fā)生了損壞。接收方會計算校驗和并與發(fā)送方發(fā)送的校驗和進行比較,如果不一致,則說明數(shù)據(jù)包發(fā)生了損壞,需要重新發(fā)送。
- 滑動窗口機制:TCP使用滑動窗口來控制發(fā)送方發(fā)送數(shù)據(jù)的速度和接收方接收數(shù)據(jù)的速度,以避免因發(fā)送速度過快或接收速度過慢而導致的數(shù)據(jù)丟失或堵塞。
- 重傳機制:如果發(fā)送方?jīng)]有收到接收方的確認消息,或者接收方收到的數(shù)據(jù)包校驗和不一致,發(fā)送方會重新發(fā)送數(shù)據(jù)包,確保數(shù)據(jù)的可靠傳輸。
- 擁塞控制:TCP具有擁塞控制機制,可以根據(jù)網(wǎng)絡的擁塞情況來調(diào)整發(fā)送數(shù)據(jù)的速率,避免網(wǎng)絡擁塞導致的數(shù)據(jù)丟失和延遲。
第一次握手,客戶端發(fā)送SYN報后,服務端回復ACK報,那這個過程中服務端內(nèi)部做了哪些工作?
服務端收到客戶端發(fā)起的 SYN 請求后,內(nèi)核會把該連接存儲到半連接隊列,并向客戶端響應 SYN+ACK,接著客戶端會返回 ACK,服務端收到第三次握手的 ACK 后,內(nèi)核會把連接從半連接隊列移除,然后創(chuàng)建新的完全的連接,并將其添加到 accept 隊列,等待進程調(diào)用 accept 函數(shù)時把連接取出來。
半連接隊列與全連接隊列不管是半連接隊列還是全連接隊列,都有最大長度限制,超過限制時,內(nèi)核會直接丟棄,或返回 RST 包。
大量SYN包發(fā)送給服務端服務端會發(fā)生什么事情?
有可能會導致TCP 半連接隊列打滿,這樣當 TCP 半連接隊列滿了,后續(xù)再在收到 SYN 報文就會丟棄,導致客戶端無法和服務端建立連接。
避免 SYN 攻擊方式,可以有以下四種方法:
- 調(diào)大 netdev_max_backlog;
- 增大 TCP 半連接隊列;
- 開啟 tcp_syncookies;
- 減少 SYN+ACK 重傳次數(shù)
方式一:調(diào)大 netdev_max_backlog
當網(wǎng)卡接收數(shù)據(jù)包的速度大于內(nèi)核處理的速度時,會有一個隊列保存這些數(shù)據(jù)包??刂圃撽犃械淖畲笾等缦?a target="_blank">參數(shù),默認值是 1000,我們要適當調(diào)大該參數(shù)的值,比如設置為 10000:
net.core.netdev_max_backlog=10000
方式二:增大 TCP 半連接隊列
增大 TCP 半連接隊列,要同時增大下面這三個參數(shù):
- 增大 net.ipv4.tcp_max_syn_backlog
- 增大 listen() 函數(shù)中的 backlog
- 增大 net.core.somaxconn
方式三:開啟 net.ipv4.tcp_syncookies
開啟 syncookies 功能就可以在不使用 SYN 半連接隊列的情況下成功建立連接,相當于繞過了 SYN 半連接來建立連接。
tcp_syncookies 應對 SYN 攻擊具體過程:
-
當 「 SYN 隊列」?jié)M之后,后續(xù)服務端收到 SYN 包,不會丟棄,而是根據(jù)算法,計算出一個
cookie
值; - 將 cookie 值放到第二次握手報文的「序列號」里,然后服務端回第二次握手給客戶端;
- 服務端接收到客戶端的應答報文時,服務端會檢查這個 ACK 包的合法性。如果合法,將該連接對象放入到「 Accept 隊列」。
-
最后應用程序通過調(diào)用
accpet()
接口,從「 Accept 隊列」取出的連接。
可以看到,當開啟了 tcp_syncookies 了,即使受到 SYN 攻擊而導致 SYN 隊列滿時,也能保證正常的連接成功建立。
net.ipv4.tcp_syncookies 參數(shù)主要有以下三個值:
- 0 值,表示關閉該功能;
- 1 值,表示僅當 SYN 半連接隊列放不下時,再啟用它;
- 2 值,表示無條件開啟功能;
那么在應對 SYN 攻擊時,只需要設置為 1 即可。
$echo1>/proc/sys/net/ipv4/tcp_syncookies
方式四:減少 SYN+ACK 重傳次數(shù)
當服務端受到 SYN 攻擊時,就會有大量處于 SYN_REVC 狀態(tài)的 TCP 連接,處于這個狀態(tài)的 TCP 會重傳 SYN+ACK ,當重傳超過次數(shù)達到上限后,就會斷開連接。
那么針對 SYN 攻擊的場景,我們可以減少 SYN-ACK 的重傳次數(shù),以加快處于 SYN_REVC 狀態(tài)的 TCP 連接斷開。
SYN-ACK 報文的最大重傳次數(shù)由 tcp_synack_retries
內(nèi)核參數(shù)決定(默認值是 5 次),比如將 tcp_synack_retries 減少到 2 次:
$echo2>/proc/sys/net/ipv4/tcp_synack_retries
服務端默認能接受多少個連接?
TCP 四元組可以唯一的確定一個連接,四元組包括如下:
- 源地址
- 源端口
- 目的地址
- 目的端口
源地址和目的地址的字段(32 位)是在 IP 頭部中,作用是通過 IP 協(xié)議發(fā)送報文給對方主機。
源端口和目的端口的字段(16 位)是在 TCP 頭部中,作用是告訴 TCP 協(xié)議應該把報文發(fā)給哪個進程。
有一個 IP 的服務端監(jiān)聽了一個端口,它的 TCP 的最大連接數(shù)是多少?
服務端通常固定在某個本地端口上監(jiān)聽,等待客戶端的連接請求。
因此,客戶端 IP 和端口是可變的,其理論值計算公式如下:
img
對 IPv4,客戶端的 IP 數(shù)最多為 2
的 32
次方,客戶端的端口數(shù)最多為 2
的 16
次方,也就是服務端單機最大 TCP 連接數(shù),約為 2
的 48
次方。
當然,服務端最大并發(fā) TCP 連接數(shù)遠不能達到理論上限,會受以下因素影響:
-
文件描述符限制
,每個 TCP 連接都是一個文件,如果文件描述符被占滿了,會發(fā)生 Too many open files。Linux 對可打開的文件描述符的數(shù)量分別作了三個方面的限制:
-
系統(tǒng)級:當前系統(tǒng)可打開的最大數(shù)量,通過
cat /proc/sys/fs/file-max
查看; -
用戶級:指定用戶可打開的最大數(shù)量,通過
cat /etc/security/limits.conf
查看; -
進程級:單個進程可打開的最大數(shù)量,通過
cat /proc/sys/fs/nr_open
查看;
-
系統(tǒng)級:當前系統(tǒng)可打開的最大數(shù)量,通過
-
內(nèi)存限制,每個 TCP 連接都要占用一定內(nèi)存,操作系統(tǒng)的內(nèi)存是有限的,如果內(nèi)存資源被占滿后,會發(fā)生 OOM。
從輸入url到頁面顯示發(fā)生了哪些事情?
圖片- 解析URL:分析 URL 所需要使用的傳輸協(xié)議和請求的資源路徑。如果輸入的 URL 中的協(xié)議或者主機名不合法,將會把地址欄中輸入的內(nèi)容傳遞給搜索引擎。如果沒有問題,瀏覽器會檢查 URL 中是否出現(xiàn)了非法字符,則對非法字符進行轉(zhuǎn)義后在進行下一過程。
- 緩存判斷:瀏覽器會判斷所請求的資源是否在緩存里,如果請求的資源在緩存里且沒有失效,那么就直接使用,否則向服務器發(fā)起新的請求。
- DNS解析:如果資源不在本地緩存,首先需要進行DNS解析。瀏覽器會向本地DNS服務器發(fā)送域名解析請求,本地DNS服務器會逐級查詢,最終找到對應的IP地址。
- 獲取MAC地址:當瀏覽器得到 IP 地址后,數(shù)據(jù)傳輸還需要知道目的主機 MAC 地址,因為應用層下發(fā)數(shù)據(jù)給傳輸層,TCP 協(xié)議會指定源端口號和目的端口號,然后下發(fā)給網(wǎng)絡層。網(wǎng)絡層會將本機地址作為源地址,獲取的 IP 地址作為目的地址。然后將下發(fā)給數(shù)據(jù)鏈路層,數(shù)據(jù)鏈路層的發(fā)送需要加入通信雙方的 MAC 地址,本機的 MAC 地址作為源 MAC 地址,目的 MAC 地址需要分情況處理。通過將 IP 地址與本機的子網(wǎng)掩碼相結(jié)合,可以判斷是否與請求主機在同一個子網(wǎng)里,如果在同一個子網(wǎng)里,可以使用 APR 協(xié)議獲取到目的主機的 MAC 地址,如果不在一個子網(wǎng)里,那么請求應該轉(zhuǎn)發(fā)給網(wǎng)關,由它代為轉(zhuǎn)發(fā),此時同樣可以通過 ARP 協(xié)議來獲取網(wǎng)關的 MAC 地址,此時目的主機的 MAC 地址應該為網(wǎng)關的地址。
- 建立TCP連接:主機將使用目標 IP地址和目標MAC地址發(fā)送一個TCP SYN包,請求建立一個TCP連接,然后交給路由器轉(zhuǎn)發(fā),等路由器轉(zhuǎn)到目標服務器后,服務器回復一個SYN-ACK包,確認連接請求。然后,主機發(fā)送一個ACK包,確認已收到服務器的確認,然后 TCP 連接建立完成。
- HTTPS 的 TLS 四次握手:如果使用的是 HTTPS 協(xié)議,在通信前還存在 TLS 的四次握手。
- 發(fā)送HTTP請求:連接建立后,瀏覽器會向服務器發(fā)送HTTP請求。請求中包含了用戶需要獲取的資源的信息,例如網(wǎng)頁的URL、請求方法(GET、POST等)等。
- 服務器處理請求并返回響應:服務器收到請求后,會根據(jù)請求的內(nèi)容進行相應的處理。例如,如果是請求網(wǎng)頁,服務器會讀取相應的網(wǎng)頁文件,并生成HTTP響應。
拿到IP地址還要去獲取MAC地址,TCP連接需要用到MAC地址嗎?
也需要的,客戶端發(fā)送第一個 syn 報文的時候,也需要在數(shù)據(jù)鏈路層組裝 mac 地址的。
DNS解析流程?
域名解析的工作流程- 客戶端首先會發(fā)出一個 DNS 請求,問 www.server.com 的 IP 是啥,并發(fā)給本地 DNS 服務器(也就是客戶端的 TCP/IP 設置中填寫的 DNS 服務器地址)。
- 本地域名服務器收到客戶端的請求后,如果緩存里的表格能找到 www.server.com,則它直接返回 IP 地址。如果沒有,本地 DNS 會去問它的根域名服務器:“老大, 能告訴我 www.server.com 的 IP 地址嗎?” 根域名服務器是最高層次的,它不直接用于域名解析,但能指明一條道路。
- 根 DNS 收到來自本地 DNS 的請求后,發(fā)現(xiàn)后置是 .com,說:“www.server.com 這個域名歸 .com 區(qū)域管理”,我給你 .com 頂級域名服務器地址給你,你去問問它吧?!?/li>
- 本地 DNS 收到頂級域名服務器的地址后,發(fā)起請求問“老二, 你能告訴我 www.server.com 的 IP 地址嗎?”
- 頂級域名服務器說:“我給你負責 www.server.com 區(qū)域的權(quán)威 DNS 服務器的地址,你去問它應該能問到”。
- 本地 DNS 于是轉(zhuǎn)向問權(quán)威 DNS 服務器:“老三,www.server.com對應的IP是啥呀?” server.com 的權(quán)威 DNS 服務器,它是域名解析結(jié)果的原出處。為啥叫權(quán)威呢?就是我的域名我做主。
- 權(quán)威 DNS 服務器查詢后將對應的 IP 地址 X.X.X.X 告訴本地 DNS。
- 本地 DNS 再將 IP 地址返回客戶端,客戶端和目標建立連接。
至此,我們完成了 DNS 的解析過程?,F(xiàn)在總結(jié)一下,整個過程我畫成了一個圖。
網(wǎng)頁非常慢轉(zhuǎn)圈圈的時候,要定位問題需要從哪些角度?
最直接的辦法就是抓包,排查的思路大概有:
-
先確定是服務端的問題,還是客戶端的問題。先確認瀏覽器是否可以訪問其他網(wǎng)站,如果不可以,說明客戶端網(wǎng)絡自身的問題,然后檢查客戶端網(wǎng)絡配置(連接wifi正不正常,有沒有插網(wǎng)線);如果可以正常其他網(wǎng)頁,說明客戶端網(wǎng)絡是可以正常上網(wǎng)的。
-
如果客戶端網(wǎng)絡沒問題,就抓包確認 DNS 是否解析出了 IP 地址,如果沒有解析出來,說明域名寫錯了,如果解析出了 IP 地址,抓包確認有沒有和服務端建立三次握手,如果能成功建立三次握手,并且發(fā)出了 HTTP 請求,但是就是沒有顯示頁面,可以查看服務端返回的響應碼:
- 如果是404錯誤碼,檢查輸入的url是否正確;
- 如果是500,說明服務器此時有問題;
- 如果是200,F(xiàn)12看看前端代碼有問題導致瀏覽器沒有渲染出頁面。
-
如果客戶端網(wǎng)絡是正常的,但是訪問速度很慢,導致很久才顯示出來。這時候要看客戶端的網(wǎng)口流量是否太大的了,導致tcp發(fā)生丟包之類的問題。
總之就是一層一層有沒有插網(wǎng)線,網(wǎng)絡配置是否正確、DNS有沒有解析出 IP地址、TCP有沒有三次握手、HTTP返回的響應碼是什么。
推薦閱讀:網(wǎng)站顯示不出來,怎么排查?
HTTP默認的端口是什么?
http 是 80,https 默認是 443。
端口通不通用什么命令?
第一種方式:telnet:telnet命令用于建立與遠程主機的Telnet連接,并可以使用telnet命令測試特定端口的可訪問性。
-
示例:
telnet IP地址 端口號
用于測試指定IP地址上的指定端口是否可訪問。如果能夠建立連接,則表示端口通暢;如果連接失敗或超時,則表示端口不可訪問。
第二種方式:nc:nc命令(也稱為netcat)是一個網(wǎng)絡工具,可以用于創(chuàng)建各種類型的網(wǎng)絡連接,包括測試端口的可訪問性。
-
示例:
nc -zv IP地址 端口號
用于測試指定IP地址上的指定端口是否可訪問。如果能夠成功連接,則表示端口通暢;如果連接失敗或拒絕,則表示端口不可訪問。
linux端口狀態(tài)查詢有哪些命令?
-
netstat -tunlp
用于顯示所有TCP和UDP端口的監(jiān)聽狀態(tài)。 -
lsof -i :端口號
用于顯示指定端口的相關信息。
ping命令走的是什么協(xié)議?
ICMP 協(xié)議。
ICMP 回送消息錯誤返回碼認識哪些?
五大類 HTTP 狀態(tài)碼-
1xx
類狀態(tài)碼屬于提示信息,是協(xié)議處理中的一種中間狀態(tài),實際用到的比較少。 -
2xx
類狀態(tài)碼表示服務器成功處理了客戶端的請求,也是我們最愿意看到的狀態(tài)。 -
3xx
類狀態(tài)碼表示客戶端請求的資源發(fā)生了變動,需要客戶端用新的 URL 重新發(fā)送請求獲取資源,也就是重定向。 -
4xx
類狀態(tài)碼表示客戶端發(fā)送的報文有誤,服務器無法處理,也就是錯誤碼的含義。 -
5xx
類狀態(tài)碼表示客戶端請求報文正確,但是服務器處理時內(nèi)部發(fā)生了錯誤,屬于服務器端的錯誤碼。
403代表什么含義?
「403 Forbidden」表示服務器禁止訪問資源,并不是客戶端的請求出錯。
常見的情況包括:
- 客戶端嘗試訪問需要身份驗證的資源,但未提供有效的憑據(jù)。
- 客戶端嘗試訪問受限制的目錄或文件。
- 客戶端的IP地址被服務器所禁止訪問。
重定向的作用?
重定向狀態(tài)碼如下,301 和 302 都會在響應頭里使用字段 Location
,指明后續(xù)要跳轉(zhuǎn)的 URL,瀏覽器會自動重定向新的 URL。
- 「301 Moved Permanently」表示永久重定向,說明請求的資源已經(jīng)不存在了,需改用新的 URL 再次訪問。
- 「302 Found」表示臨時重定向,說明請求的資源還在,但暫時需要用另一個 URL 來訪問。
重定向是指將一個URL請求轉(zhuǎn)發(fā)到另一個URL的過程。重定向的作用包括:
-
更改URL:通過重定向,可以更改URL,使其更易于記憶、更友好或更有意義。例如,將長而復雜的URL重定向到簡潔的、易于理解的URL。
-
網(wǎng)站遷移:當網(wǎng)站進行重構(gòu)、更換域名或更改URL結(jié)構(gòu)時,通過重定向舊的URL到新的URL,可以讓用戶和搜索引擎正確地訪問和索引新的內(nèi)容。
反向代理,那正向代理是什么?
圖片來源:ByteByteGo- 正向代理是位于用戶設備和互聯(lián)網(wǎng)之間的服務器。它代理的是客戶端,是站在用戶一方的。其真實客戶端對于服務器不可見。
- 反向代理是一種服務器,它接受客戶端的請求,將請求轉(zhuǎn)發(fā)給網(wǎng)絡服務器,然后將結(jié)果返回給客戶端,就像代理服務器處理了請求一樣。
推薦閱讀:面試官:你背一下負載均衡算法?
TCP的擁塞控制介紹一下?
擁塞控制是用于在網(wǎng)絡擁塞時減少網(wǎng)絡流量和避免網(wǎng)絡崩潰。
TCP的擁塞控制機制主要包括以下幾個方面:
-
慢啟動:當建立連接或恢復丟失的數(shù)據(jù)包時,TCP會以指數(shù)增加的方式逐漸增加發(fā)送窗口的大小,從而逐漸增加發(fā)送的數(shù)據(jù)量。
-
擁塞避免:在慢啟動階段,當檢測到網(wǎng)絡擁塞時,TCP會切換到擁塞避免模式。擁塞避免使用線性增加的方式逐漸增加發(fā)送窗口的大小,以降低網(wǎng)絡擁塞的風險。
-
快速重傳:當發(fā)送方連續(xù)接收到同一個確認號的重復確認時,它會認為該數(shù)據(jù)包已經(jīng)丟失,并立即重新發(fā)送丟失的數(shù)據(jù)包,而不等待超時重傳。
-
快速恢復:在快速重傳后,發(fā)送方會將擁塞窗口減半,并使用擁塞避免模式逐漸增加發(fā)送窗口的大小,以便恢復正常的發(fā)送速率。
通過這些機制,TCP能夠根據(jù)網(wǎng)絡的擁塞情況動態(tài)調(diào)整發(fā)送窗口的大小和發(fā)送速率,以避免網(wǎng)絡擁塞并保證數(shù)據(jù)的可靠傳輸。擁塞控制是TCP協(xié)議的重要特性,它在保持網(wǎng)絡穩(wěn)定和高效運行方面起著重要作用。
HTTP層請求的類型有哪些?
-
GET:用于請求獲取指定資源,通常用于獲取數(shù)據(jù)。
-
POST:用于向服務器提交數(shù)據(jù),通常用于提交表單數(shù)據(jù)或進行資源的創(chuàng)建。
-
PUT:用于向服務器更新指定資源,通常用于更新已存在的資源。
-
DELETE:用于請求服務器刪除指定資源。
-
HEAD:類似于GET請求,但只返回資源的頭部信息,用于獲取資源的元數(shù)據(jù)而不獲取實際內(nèi)容。
GET和POST的使用場景,有哪些區(qū)別?
根據(jù) RFC 規(guī)范,GET 的語義是從服務器獲取指定的資源,這個資源可以是靜態(tài)的文本、頁面、圖片視頻等。GET 請求的參數(shù)位置一般是寫在 URL 中,URL 規(guī)定只能支持 ASCII,所以 GET 請求的參數(shù)只允許 ASCII 字符 ,而且瀏覽器會對 URL 的長度有限制(HTTP協(xié)議本身對 URL長度并沒有做任何規(guī)定)。
比如,你打開我的文章,瀏覽器就會發(fā)送 GET 請求給服務器,服務器就會返回文章的所有文字及資源。
GET 請求根據(jù) RFC 規(guī)范,POST 的語義是根據(jù)請求負荷(報文body)對指定的資源做出處理,具體的處理方式視資源類型而不同。POST 請求攜帶數(shù)據(jù)的位置一般是寫在報文 body 中,body 中的數(shù)據(jù)可以是任意格式的數(shù)據(jù),只要客戶端與服務端協(xié)商好即可,而且瀏覽器不會對 body 大小做限制。
比如,你在我文章底部,敲入了留言后點擊「提交」(暗示你們留言),瀏覽器就會執(zhí)行一次 POST 請求,把你的留言文字放進了報文 body 里,然后拼接好 POST 請求頭,通過 TCP 協(xié)議發(fā)送給服務器。
POST 請求如果從 RFC 規(guī)范定義的語義來看:
- GET 方法就是安全且冪等的,因為它是「只讀」操作,無論操作多少次,服務器上的數(shù)據(jù)都是安全的,且每次的結(jié)果都是相同的。所以,可以對 GET 請求的數(shù)據(jù)做緩存,這個緩存可以做到瀏覽器本身上(徹底避免瀏覽器發(fā)請求),也可以做到代理上(如nginx),而且在瀏覽器中 GET 請求可以保存為書簽。
- POST 因為是「新增或提交數(shù)據(jù)」的操作,會修改服務器上的資源,所以是不安全的,且多次提交數(shù)據(jù)就會創(chuàng)建多個資源,所以不是冪等的。所以,瀏覽器一般不會緩存 POST 請求,也不能把 POST 請求保存為書簽。
但是實際過程中,開發(fā)者不一定會按照 RFC 規(guī)范定義的語義來實現(xiàn) GET 和 POST 方法。比如:
- 可以用 GET 方法實現(xiàn)新增或刪除數(shù)據(jù)的請求,這樣實現(xiàn)的 GET 方法自然就不是安全和冪等。
- 可以用 POST 方法實現(xiàn)查詢數(shù)據(jù)的請求,這樣實現(xiàn)的 POST 方法自然就是安全和冪等。
HTTP的長連接是什么?
HTTP 協(xié)議采用的是「請求-應答」的模式,也就是客戶端發(fā)起了請求,服務端才會返回響應,一來一回這樣子。
請求-應答由于 HTTP 是基于 TCP 傳輸協(xié)議實現(xiàn)的,客戶端與服務端要進行 HTTP 通信前,需要先建立 TCP 連接,然后客戶端發(fā)送 HTTP 請求,服務端收到后就返回響應,至此「請求-應答」的模式就完成了,隨后就會釋放 TCP 連接。
一個 HTTP 請求如果每次請求都要經(jīng)歷這樣的過程:建立 TCP -> 請求資源 -> 響應資源 -> 釋放連接,那么此方式就是 HTTP 短連接,如下圖:
HTTP 短連接這樣實在太累人了,一次連接只能請求一次資源。
能不能在第一個 HTTP 請求完后,先不斷開 TCP 連接,讓后續(xù)的 HTTP 請求繼續(xù)使用此連接?
當然可以,HTTP 的 Keep-Alive 就是實現(xiàn)了這個功能,可以使用同一個 TCP 連接來發(fā)送和接收多個 HTTP 請求/應答,避免了連接建立和釋放的開銷,這個方法稱為 HTTP 長連接。
HTTP 長連接HTTP 長連接的特點是,只要任意一端沒有明確提出斷開連接,則保持 TCP 連接狀態(tài)。
HTTP長連接與WebSocket有什么區(qū)別?
- 全雙工和半雙工:TCP 協(xié)議本身是全雙工的,但我們最常用的 HTTP/1.1,雖然是基于 TCP 的協(xié)議,但它是半雙工的,對于大部分需要服務器主動推送數(shù)據(jù)到客戶端的場景,都不太友好,因此我們需要使用支持全雙工的 WebSocket 協(xié)議。
- 應用場景區(qū)別:在 HTTP/1.1 里,只要客戶端不問,服務端就不答?;谶@樣的特點,對于登錄頁面這樣的簡單場景,可以使用定時輪詢或者長輪詢的方式實現(xiàn)服務器推送(comet)的效果。對于客戶端和服務端之間需要頻繁交互的復雜場景,比如網(wǎng)頁游戲,都可以考慮使用 WebSocket 協(xié)議。
操作系統(tǒng)
進程跟線程的區(qū)別?
- 本質(zhì)區(qū)別:進程是操作系統(tǒng)資源分配的基本單位,而線程是任務調(diào)度和執(zhí)行的基本單位
- 在開銷方面:每個進程都有獨立的代碼和數(shù)據(jù)空間(程序上下文),程序之間的切換會有較大的開銷;線程可以看做輕量級的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程都有自己獨立的運行棧和程序計數(shù)器(PC),線程之間切換的開銷小
- 所處環(huán)境:在操作系統(tǒng)中能同時運行多個進程(程序);而在同一個進程(程序)中有多個線程同時執(zhí)行(通過CPU調(diào)度,在每個時間片中只有一個線程執(zhí)行)
- 內(nèi)存分配方面:系統(tǒng)在運行的時候會為每個進程分配不同的內(nèi)存空間;而對線程而言,除了CPU外,系統(tǒng)不會為線程分配內(nèi)存(線程所使用的資源來自其所屬進程的資源),線程組之間只能共享資源
- 包含關系:沒有線程的進程可以看做是單線程的,如果一個進程內(nèi)有多個線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共同完成的;線程是進程的一部分,所以線程也被稱為輕權(quán)進程或者輕量級進程
舉個例子:進程=火車,線程=車廂
- 線程在進程下行進(單純的車廂無法運行)
- 一個進程可以包含多個線程(一輛火車可以有多個車廂)
- 不同進程間數(shù)據(jù)很難共享(一輛火車上的乘客很難換到另外一輛火車,比如站點換乘)
- 同一進程下不同線程間數(shù)據(jù)很易共享(A車廂換到B車廂很容易)
- 進程要比線程消耗更多的計算機資源(采用多列火車相比多個車廂更耗資源)
- 進程間不會相互影響,一個線程掛掉將導致整個進程掛掉(一列火車不會影響到另外一列火車,但是如果一列火車上中間的一節(jié)車廂著火了,將影響到所有車廂)
多線程是不是越多越好,太多會有什么問題?
多線程不一定越多越好,過多的線程可能會導致一些問題。
- 切換開銷:線程的創(chuàng)建和切換會消耗系統(tǒng)資源,包括內(nèi)存和CPU。如果創(chuàng)建太多線程,會占用大量的系統(tǒng)資源,導致系統(tǒng)負載過高,某個線程崩潰后,可能會導致進程崩潰。
- 死鎖的問題:過多的線程可能會導致競爭條件和死鎖。競爭條件指的是多個線程同時訪問和修改共享資源,如果沒有合適的同步機制,可能會導致數(shù)據(jù)不一致或錯誤的結(jié)果。而死鎖則是指多個線程相互等待對方釋放資源,導致程序無法繼續(xù)執(zhí)行。
進程調(diào)度算法有哪些?
01 先來先服務調(diào)度算法
最簡單的一個調(diào)度算法,就是非搶占式的先來先服務(*First Come First Serve, FCFS*)算法了。
FCFS 調(diào)度算法
顧名思義,先來后到,每次從就緒隊列選擇最先進入隊列的進程,然后一直運行,直到進程退出或被阻塞,才會繼續(xù)從隊列中選擇第一個進程接著運行。
這似乎很公平,但是當一個長作業(yè)先運行了,那么后面的短作業(yè)等待的時間就會很長,不利于短作業(yè)。
FCFS 對長作業(yè)有利,適用于 CPU 繁忙型作業(yè)的系統(tǒng),而不適用于 I/O 繁忙型作業(yè)的系統(tǒng)。
02 最短作業(yè)優(yōu)先調(diào)度算法
最短作業(yè)優(yōu)先(*Shortest Job First, SJF*)調(diào)度算法同樣也是顧名思義,它會優(yōu)先選擇運行時間最短的進程來運行,這有助于提高系統(tǒng)的吞吐量。
SJF 調(diào)度算法
這顯然對長作業(yè)不利,很容易造成一種極端現(xiàn)象。
比如,一個長作業(yè)在就緒隊列等待運行,而這個就緒隊列有非常多的短作業(yè),那么就會使得長作業(yè)不斷的往后推,周轉(zhuǎn)時間變長,致使長作業(yè)長期不會被運行。
03 高響應比優(yōu)先調(diào)度算法
前面的「先來先服務調(diào)度算法」和「最短作業(yè)優(yōu)先調(diào)度算法」都沒有很好的權(quán)衡短作業(yè)和長作業(yè)。
那么,高響應比優(yōu)先 (*Highest Response Ratio Next, HRRN*)調(diào)度算法主要是權(quán)衡了短作業(yè)和長作業(yè)。
每次進行進程調(diào)度時,先計算「響應比優(yōu)先級」,然后把「響應比優(yōu)先級」最高的進程投入運行,「響應比優(yōu)先級」的計算公式:
從上面的公式,可以發(fā)現(xiàn):
- 如果兩個進程的「等待時間」相同時,「要求的服務時間」越短,「響應比」就越高,這樣短作業(yè)的進程容易被選中運行;
- 如果兩個進程「要求的服務時間」相同時,「等待時間」越長,「響應比」就越高,這就兼顧到了長作業(yè)進程,因為進程的響應比可以隨時間等待的增加而提高,當其等待時間足夠長時,其響應比便可以升到很高,從而獲得運行的機會;
04 時間片輪轉(zhuǎn)調(diào)度算法
最古老、最簡單、最公平且使用最廣的算法就是時間片輪轉(zhuǎn)(*Round Robin, RR*)調(diào)度算法。
RR 調(diào)度算法
每個進程被分配一個時間段,稱為時間片(*Quantum*),即允許該進程在該時間段中運行。
- 如果時間片用完,進程還在運行,那么將會把此進程從 CPU 釋放出來,并把 CPU 分配給另外一個進程;
- 如果該進程在時間片結(jié)束前阻塞或結(jié)束,則 CPU 立即進行切換;
另外,時間片的長度就是一個很關鍵的點:
- 如果時間片設得太短會導致過多的進程上下文切換,降低了 CPU 效率;
- 如果設得太長又可能引起對短作業(yè)進程的響應時間變長。將
一般來說,時間片設為 20ms~50ms
通常是一個比較合理的折中值。
05 最高優(yōu)先級調(diào)度算法
前面的「時間片輪轉(zhuǎn)算法」做了個假設,即讓所有的進程同等重要,也不偏袒誰,大家的運行時間都一樣。
但是,對于多用戶計算機系統(tǒng)就有不同的看法了,它們希望調(diào)度是有優(yōu)先級的,即希望調(diào)度程序能從就緒隊列中選擇最高優(yōu)先級的進程進行運行,這稱為最高優(yōu)先級(*Highest Priority First,HPF*)調(diào)度算法。
進程的優(yōu)先級可以分為,靜態(tài)優(yōu)先級和動態(tài)優(yōu)先級:
- 靜態(tài)優(yōu)先級:創(chuàng)建進程時候,就已經(jīng)確定了優(yōu)先級了,然后整個運行時間優(yōu)先級都不會變化;
- 動態(tài)優(yōu)先級:根據(jù)進程的動態(tài)變化調(diào)整優(yōu)先級,比如如果進程運行時間增加,則降低其優(yōu)先級,如果進程等待時間(就緒隊列的等待時間)增加,則升高其優(yōu)先級,也就是隨著時間的推移增加等待進程的優(yōu)先級。
該算法也有兩種處理優(yōu)先級高的方法,非搶占式和搶占式:
- 非搶占式:當就緒隊列中出現(xiàn)優(yōu)先級高的進程,運行完當前進程,再選擇優(yōu)先級高的進程。
- 搶占式:當就緒隊列中出現(xiàn)優(yōu)先級高的進程,當前進程掛起,調(diào)度優(yōu)先級高的進程運行。
但是依然有缺點,可能會導致低優(yōu)先級的進程永遠不會運行。
06 多級反饋隊列調(diào)度算法
多級反饋隊列(*Multilevel Feedback Queue*)調(diào)度算法是「時間片輪轉(zhuǎn)算法」和「最高優(yōu)先級算法」的綜合和發(fā)展。
顧名思義:
- 「多級」表示有多個隊列,每個隊列優(yōu)先級從高到低,同時優(yōu)先級越高時間片越短。
- 「反饋」表示如果有新的進程加入優(yōu)先級高的隊列時,立刻停止當前正在運行的進程,轉(zhuǎn)而去運行優(yōu)先級高的隊列;
多級反饋隊列
來看看,它是如何工作的:
- 設置了多個隊列,賦予每個隊列不同的優(yōu)先級,每個隊列優(yōu)先級從高到低,同時優(yōu)先級越高時間片越短;
- 新的進程會被放入到第一級隊列的末尾,按先來先服務的原則排隊等待被調(diào)度,如果在第一級隊列規(guī)定的時間片沒運行完成,則將其轉(zhuǎn)入到第二級隊列的末尾,以此類推,直至完成;
- 當較高優(yōu)先級的隊列為空,才調(diào)度較低優(yōu)先級的隊列中的進程運行。如果進程運行時,有新進程進入較高優(yōu)先級的隊列,則停止當前運行的進程并將其移入到原隊列末尾,接著讓較高優(yōu)先級的進程運行;
可以發(fā)現(xiàn),對于短作業(yè)可能可以在第一級隊列很快被處理完。對于長作業(yè),如果在第一級隊列處理不完,可以移入下次隊列等待被執(zhí)行,雖然等待的時間變長了,但是運行時間也變更長了,所以該算法很好的兼顧了長短作業(yè),同時有較好的響應時間。
數(shù)據(jù)庫
MySQL和Redis的區(qū)別,應用場景?
MySQL 是關系型數(shù)據(jù)庫,適用于需要保持數(shù)據(jù)一致性、進行復雜的數(shù)據(jù)分析和關聯(lián)查詢的場景。
Redis是一種基于內(nèi)存的數(shù)據(jù)存儲系統(tǒng),它主要用于緩存和高速數(shù)據(jù)訪問。Redis適合處理高速讀寫和緩存需求,適用于需要快速響應和高并發(fā)的場景,例如實時計數(shù)器、會話緩存、消息隊列、發(fā)布/訂閱系統(tǒng)等。
一般會用Redis 作為MySQL的緩存,主要是因為 Redis 具備「高性能」和「高并發(fā)」兩種特性。
1、Redis 具備高性能
假如用戶第一次訪問 MySQL 中的某些數(shù)據(jù)。這個過程會比較慢,因為是從硬盤上讀取的。將該用戶訪問的數(shù)據(jù)緩存在 Redis 中,這樣下一次再訪問這些數(shù)據(jù)的時候就可以直接從緩存中獲取了,操作 Redis 緩存就是直接操作內(nèi)存,所以速度相當快。
img如果 MySQL 中的對應數(shù)據(jù)改變的之后,同步改變 Redis 緩存中相應的數(shù)據(jù)即可,不過這里會有 Redis 和 MySQL 雙寫一致性的問題,后面我們會提到。
2、Redis 具備高并發(fā)
單臺設備的 Redis 的 QPS(Query Per Second,每秒鐘處理完請求的次數(shù)) 是 MySQL 的 10 倍,Redis 單機的 QPS 能輕松破 10w,而 MySQL 單機的 QPS 很難破 1w。
所以,直接訪問 Redis 能夠承受的請求是遠遠大于直接訪問 MySQL 的,所以我們可以考慮把數(shù)據(jù)庫中的部分數(shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶的一部分請求會直接到緩存這里而不用經(jīng)過數(shù)據(jù)庫。
MySQL有哪些存儲引擎?有什么區(qū)別?
-
InnoDB:支持事務處理,支持外鍵,支持崩潰修復能力和并發(fā)控制。如果需要對事務的完整性要求比較高(比如銀行),要求實現(xiàn)并發(fā)控制(比如售票),那選擇InnoDB有很大的優(yōu)勢。如果需要頻繁的更新、刪除操作的數(shù)據(jù)庫,也可以選擇InnoDB,因為支持事務的提交(commit)和回滾(rollback)。
-
MyISAM:插入數(shù)據(jù)快,空間和內(nèi)存使用比較低。如果表主要是用于插入新記錄和讀出記錄,那么選擇MyISAM能實現(xiàn)處理高效率。如果應用的完整性、并發(fā)性要求比 較低,也可以使用。如果數(shù)據(jù)表主要用來插入和查詢記錄,則MyISAM引擎能提供較高的處理效率
-
MEMORY:所有的數(shù)據(jù)都在內(nèi)存中,數(shù)據(jù)的處理速度快,但是安全性不高。如果需要很快的讀寫速度,對數(shù)據(jù)的安全性要求較低,可以選擇MEMOEY。它對表的大小有要求,不能建立太大的表。所以,這類數(shù)據(jù)庫只使用在相對較小的數(shù)據(jù)庫表。如果只是臨時存放數(shù)據(jù),數(shù)據(jù)量不大,并且不需要較高的數(shù)據(jù)安全性,可以選擇將數(shù)據(jù)保存在內(nèi)存中的Memory引擎,MySQL中使用該引擎作為臨時表,存放查詢的中間結(jié)果
事務用來解決什么問題?
事務用于解決數(shù)據(jù)庫操作中的一致性和持久性問題。
-
一致性問題指的是在多個并發(fā)操作中,如果其中一個操作失敗或發(fā)生錯誤,可能導致數(shù)據(jù)處于不一致的狀態(tài),不符合預期的要求。
-
持久性問題指的是確保已提交的數(shù)據(jù)在數(shù)據(jù)庫系統(tǒng)
事務的四大特性主要是:
- 原子性(Atomicity):一個事務中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié),而且事務在執(zhí)行過程中發(fā)生錯誤,會被回滾到事務開始前的狀態(tài),就像這個事務從來沒有執(zhí)行過一樣,就好比買一件商品,購買成功時,則給商家付了錢,商品到手;購買失敗時,則商品在商家手中,消費者的錢也沒花出去。
- 一致性(Consistency):是指事務操作前和操作后,數(shù)據(jù)滿足完整性約束,數(shù)據(jù)庫保持一致性狀態(tài)。比如,用戶 A 和用戶 B 在銀行分別有 800 元和 600 元,總共 1400 元,用戶 A 給用戶 B 轉(zhuǎn)賬 200 元,分為兩個步驟,從 A 的賬戶扣除 200 元和對 B 的賬戶增加 200 元。一致性就是要求上述步驟操作后,最后的結(jié)果是用戶 A 還有 600 元,用戶 B 有 800 元,總共 1400 元,而不會出現(xiàn)用戶 A 扣除了 200 元,但用戶 B 未增加的情況(該情況,用戶 A 和 B 均為 600 元,總共 1200 元)。
- 隔離性(Isolation):數(shù)據(jù)庫允許多個并發(fā)事務同時對其數(shù)據(jù)進行讀寫和修改的能力,隔離性可以防止多個事務并發(fā)執(zhí)行時由于交叉執(zhí)行而導致數(shù)據(jù)的不一致,因為多個事務同時使用相同的數(shù)據(jù)時,不會相互干擾,每個事務都有一個完整的數(shù)據(jù)空間,對其他并發(fā)事務是隔離的。也就是說,消費者購買商品這個事務,是不影響其他消費者購買的。
- 持久性(Durability):事務處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。
MySQL存儲的數(shù)據(jù)結(jié)構(gòu)是怎么樣的?
InnoDB 存儲引擎的索引結(jié)構(gòu)是 b+樹。
選擇 b+樹作為數(shù)據(jù)結(jié)構(gòu)的原因是:
- B+Tree vs B Tree:B+Tree 只在葉子節(jié)點存儲數(shù)據(jù),而 B 樹 的非葉子節(jié)點也要存儲數(shù)據(jù),所以 B+Tree 的單個節(jié)點的數(shù)據(jù)量更小,在相同的磁盤 I/O 次數(shù)下,就能查詢更多的節(jié)點。另外,B+Tree 葉子節(jié)點采用的是雙鏈表連接,適合 MySQL 中常見的基于范圍的順序查找,而 B 樹無法做到這一點。
-
B+Tree vs 二叉樹:對于有 N 個葉子節(jié)點的 B+Tree,其搜索復雜度為
O(logdN)
,其中 d 表示節(jié)點允許的最大子節(jié)點個數(shù)為 d 個。在實際的應用當中, d 值是大于100的,這樣就保證了,即使數(shù)據(jù)達到千萬級別時,B+Tree 的高度依然維持在 3~4 層左右,也就是說一次數(shù)據(jù)查詢操作只需要做 3~4 次的磁盤 I/O 操作就能查詢到目標數(shù)據(jù)。而二叉樹的每個父節(jié)點的兒子節(jié)點個數(shù)只能是 2 個,意味著其搜索復雜度為O(logN)
,這已經(jīng)比 B+Tree 高出不少,因此二叉樹檢索到目標數(shù)據(jù)所經(jīng)歷的磁盤 I/O 次數(shù)要更多。 - B+Tree vs Hash:Hash 在做等值查詢的時候效率賊快,搜索復雜度為 O(1)。但是 Hash 表不適合做范圍查詢,它更適合做等值的查詢,這也是 B+Tree 索引要比 Hash 表索引有著更廣泛的適用場景的原因。
Text數(shù)據(jù)類型可以無限大嗎?
MySQL 3 種text類型的最大長度如下:
- TEXT:65,535 bytes ~64kb
- MEDIUMTEXT:16,777,215 bytes ~16Mb
- LONGTEXT:4,294,967,295 bytes ~4Gb
MySQL索引的優(yōu)缺點?
索引最大的好處是提高查詢速度,但是索引也是有缺點的,比如:
- 需要占用物理空間,數(shù)量越大,占用空間越大;
- 創(chuàng)建索引和維護索引要耗費時間,這種時間隨著數(shù)據(jù)量的增加而增大;
- 會降低表的增刪改的效率,因為每次增刪改索引,B+ 樹為了維護索引有序性,都需要進行動態(tài)維護。
所以,索引不是萬能鑰匙,它也是根據(jù)場景來使用的。
什么時候不適合用索引?
-
WHERE
條件,GROUP BY
,ORDER BY
里用不到的字段,索引的價值是快速定位,如果起不到定位的字段通常是不需要創(chuàng)建索引的,因為索引是會占用物理空間的。 - 字段中存在大量重復數(shù)據(jù),不需要創(chuàng)建索引,比如性別字段,只有男女,如果數(shù)據(jù)庫表中,男女的記錄分布均勻,那么無論搜索哪個值都可能得到一半的數(shù)據(jù)。在這些情況下,還不如不要索引,因為 MySQL 還有一個查詢優(yōu)化器,查詢優(yōu)化器發(fā)現(xiàn)某個值出現(xiàn)在表的數(shù)據(jù)行中的百分比很高的時候,它一般會忽略索引,進行全表掃描。
- 表數(shù)據(jù)太少的時候,不需要創(chuàng)建索引;
- 經(jīng)常更新的字段不用創(chuàng)建索引,比如不要對電商項目的用戶余額建立索引,因為索引字段頻繁修改,由于要維護 B+Tree的有序性,那么就需要頻繁的重建索引,這個過程是會影響數(shù)據(jù)庫性能的。
算法
- 實現(xiàn) LRU算法實現(xiàn)(鏈表+hashmap)
#include
#include
#include
classLRUCache{
private:
intcapacity;
std::unordered_map<int,std::list<std::pair<int,int>>::iterator>cache;
std::list<std::pair<int,int>>lruList;
public:
LRUCache(intcapacity){
this->capacity=capacity;
}
intget(intkey){
if(cache.find(key)==cache.end()){
return-1;//如果key不存在,返回-1
}
//將訪問的節(jié)點移動到鏈表頭部
std::pair<int,int>keyValue=*cache[key];
lruList.erase(cache[key]);
lruList.push_front(keyValue);
cache[key]=lruList.begin();
returnkeyValue.second;
}
voidput(intkey,intvalue){
if(cache.find(key)==cache.end()){
//如果容量已滿,移除最久未使用的節(jié)點
if(lruList.size()==capacity){
std::pair<int,int>lastPair=lruList.back();
intlastKey=lastPair.first;
cache.erase(lastKey);
lruList.pop_back();
}
//將新節(jié)點添加到鏈表頭部
lruList.push_front(std::make_pair(key,value));
cache[key]=lruList.begin();
}else{
//如果key已存在,更新節(jié)點的值,并將節(jié)點移動到鏈表頭部
lruList.erase(cache[key]);
lruList.push_front(std::make_pair(key,value));
cache[key]=lruList.begin();
}
}
};
intmain(){
LRUCachecache(2);
cache.put(1,1);
cache.put(2,2);
std::cout<1)<std::endl;//輸出1
cache.put(3,3);
std::cout<2)<std::endl;//輸出-1
cache.put(4,4);
std::cout<1)<std::endl;//輸出-1
std::cout<3)<std::endl;//輸出3
std::cout<4)<std::endl;//輸出4
return0;
}
-
數(shù)據(jù)傳輸
+關注
關注
9文章
1919瀏覽量
64673 -
傳輸層
+關注
關注
0文章
30瀏覽量
10913 -
網(wǎng)絡模型
+關注
關注
0文章
44瀏覽量
8445
原文標題:騰訊有點頂,連環(huán)追問我基礎細節(jié)!
文章出處:【微信號:小林coding,微信公眾號:小林coding】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論