上篇:靠著阿裡師兄給的170 道 Python 面試題,我已成功上岸【Python基礎篇】
綜合篇:網絡編程
101. 簡述 OSI 七層協議
102. 三次握手、四次揮手的流程
103. 什麼是 C/S 和 B/S 架構
104. TCP 和 UDP 的區別
105. 局域網和廣域網
106. arp 協議
107. 什麼是 socket?簡述基於 TCP 協議的套接字通信流程
108. 簡述 進程、線程、協程的區別以及應用場景
109. 如何使用線程池和進程池
110. 進程之間如何進行通信
111. 進程鎖和線程鎖
112. 什麼是並發和並行
113. threading.local 的作用
114. 什麼是域名解析
115. LVS 是什麼及作用
116. Nginx 的作用
117. keepalived 及 HAProxy
118. 什麼是 rpc
119. 從浏覽器輸入一個網址到展示網址頁面的過程
120. 什麼是cdn
是網絡傳輸協議,人為的把網絡傳輸的不同階段劃分成不同的層次
七層劃分為:應用層、表示層、會話層、傳輸層、網絡層、數據鏈路層、物理層
五層劃分為:應用層、傳輸層、網絡層、數據鏈路層、物理層
物理層:網線,電纜等物理設備
數據鏈路層:Mac 地址
網絡層:IP 地址
傳輸層:TCP,UDP 協議
應用層:FTP 協議,Email,WWW 等
都發生在傳輸層
三次握手:
TCP 協議是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接。TCP 標志位(位碼),有6種標示:SYN(synchronous建立聯機) ACK(acknowledgement 確認) PSH(push傳送) FIN(finish結束) RST(reset重置) URG(urgent緊急) Sequence number(順序號碼) Acknowledge number(確認號碼) 第一次握手:主機 A 發送位碼為 syn=1,隨機產生 seq number=1234567 的數據包到服務器,並進入 SYN_SEND 狀態,主機 B 由 SYN=1 知道,A 要求建立聯機
第二次握手:主機 B 收到請求後要確認聯機信息,向 A 發送 ack number=(主機 A 的 seq+1),syn=1,ack=1,隨機產生 seq=7654321 的包,並進入 SYN_RECV 狀態
第三次握手:主機 A 收到後檢查 ack number 是否正確,即第一次發送的 seq number+1,以及位碼 ack 是否為 1,若正確,主機 A 會再發送 ack number=(主機 B 的 seq+1),ack=1,主機 B 收到後確認 seq 值與 ack=1 則連接建立成功,兩個主機均進入 ESTABLISHED 狀態
以上完成三次握手,主機 A 與主機 B 開始傳送數據
四次揮手:
因為 TCP 連接是全雙工的,因此每個方向都必須單獨進行關閉。這個原則是當一方完成它的數據發送任務後就能發送一個 FIN 來終止這個方向的連接。收到一個 FIN 只意味著這一方向上沒有數據流動,一個 TCP 連接在收到一個 FIN 後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉
服務器 A 發送一個 FIN,用來關閉 A 到服務器 B 的數據傳送。服務器 B 收到這個 FIN,它發回一個 ACK,確認序號為收到的序號加1。和 SYN 一樣,一個 FIN 將占用一個序號
服務器 B 關閉與服務器 A 的連接,發送一個 FIN 給服務器 A
服務器 A 發回 ACK 報文確認,並將確認序號設置為收到序號加1
B/S 又稱為浏覽器/服務器模式。比如各種網站,jupyter notebook 等。優點:零安裝,維護簡單,共享性好。缺點:安全性較差,個性化不足
C/S 又稱為客戶端/服務器模式。比如微信客戶端,Oracle 客戶端等。優點:安全性好,數據傳輸較快,穩定。缺點:對 PC 機操作系統等有要求,當客戶端較多時,服務器端負載較大
TCP 和 UDP 都是 OSI 模型中運輸層的協議。TCP 提供可靠的通信傳輸,而 UDP 則常被用於廣播和細節控制交給應用的通信傳輸。UDP 不提供復雜的控制機制,利用 IP 提供面向無連接的通信服務。TCP 充分實現了數據傳輸時各種控制功能,可以進行丟包的重發控制,還可以對次序亂掉的分包進行順序控制
TCP 應用:FTP 傳輸,點對點短信等
UDP 應用:媒體流等
廣域網(WAN,Wide Area Network)也稱遠程網(long haul network )。通常跨接很大的物理范圍,所覆蓋的范圍從幾十公裡到幾千公裡,它能連接多個城市或國家,或橫跨幾個洲並能提供遠距離通信,形成國際性的遠程網絡
域網(Local Area Network,LAN)是指在某一區域內由多台計算機互聯成的計算機組。一般是方圓幾千米以內。局域網可以實現文件管理、應用軟件共享、打印機共享、工作組內的日程安排、電子郵件和傳真通信服務等功能。局域網是封閉型的,可以由辦公室內的兩台計算機組成,也可以由一個公司內的上千台計算機組成
ARP(Address Resolution Protocol)即地址解析協議, 用於實現從 IP 地址到 MAC 地址的映射,即詢問目標 IP 對應的 MAC 地址
socket 是對 TCP/IP 協議的封裝,它的出現只是使得程序員更方便地使用 TCP/IP 協議棧而已。socket 本身並不是協議,它是應用層與 TCP/IP 協議族通信的中間軟件抽象層,是一組調用接口(TCP/IP網絡的API函數)
“TCP/IP 只是一個協議棧,就像操作系統的運行機制一樣,必須要具體實現,同時還要提供對外的操作接口。 這個就像操作系統會提供標准的編程接口,比如win32編程接口一樣。TCP/IP 也要提供可供程序員做網絡開發所用的接口,這就是 Socket 編程接口。”
Server:
import socket
import threading
def tcplink(sock, addr):
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 監聽端口:
s.bind(('127.0.0.1', 9999))
s.listen(5)
print('Waiting for connection...')
while True:
# 接受一個新連接:
sock, addr = s.accept()
# 創建新線程來處理TCP連接:
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連接:
s.connect(('127.0.0.1', 9999))
# 接收歡迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
# 發送數據:
s.send(data)
print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()
例子來源於廖雪峰的官網
進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每個進程都有自己的獨立內存空間,不同進程通過進程間通信來通信
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧
多進程:密集 CPU 任務,需要充分使用多核 CPU 資源(服務器,大量的並行計算)的時候,用多進程。 缺陷:多個進程之間通信成本高,切換開銷大
多線程:密集 I/O 任務(網絡 I/O,磁盤 I/O,數據庫 I/O)使用多線程合適。缺陷:同一個時間切片只能運行一個線程,不能做到高並行,但是可以做到高並發
協程:又稱微線程,在單線程上執行多個任務,用函數切換,開銷極小。不通過操作系統調度,沒有進程、線程的切換開銷。缺陷:單線程執行,處理密集 CPU 和本地磁盤 IO 的時候,性能較低。處理網絡 I/O 性能還是比較高
多線程請求返回是無序的,哪個線程有數據返回就處理哪個線程,而協程返回的數據是有序的
池的功能是限制啟動的進程數或線程數。當並發的任務數遠遠超過了計算機的承受能力時,即無法一次性開啟過多的進程數或線程數時,就應該用池的概念將開啟的進程數或線程數限制在計算機可承受的范圍內
多進程
from multiprocessing import Pool
import os
import time
import random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
def test_pool():
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
if __name__ == '__main__':
test_pool()
output
Parent process 32432.
Waiting for all subprocesses done...
Run task 0 (15588)...
Run task 1 (32372)...
Run task 2 (12440)...
Run task 3 (18956)...
Task 2 runs 0.72 seconds.
Run task 4 (12440)...
Task 3 runs 0.82 seconds.
Task 1 runs 1.21 seconds.
Task 0 runs 3.00 seconds.
Task 4 runs 2.95 seconds.
All subprocesses done.
apply_async(func[, args[, kwds]]) :使用非阻塞方式調用 func(並行執行,堵塞方式必須等待上一個進程退出才能執行下一個進程),args 為傳遞給 func 的參數列表,kwds 為傳遞給 func 的關鍵字參數列表;close():關閉 Pool,使其不再接受新的任務;terminate():不管任務是否完成,立即終止;join():主進程阻塞,等待子進程的退出, 必須在 close 或 terminate 之後使用
也可以使用 concurrent.futures 模塊提供的功能來實現
def test_future_process():
print('Parent process %s.' % os.getpid())
p = ProcessPoolExecutor(4)
for i in range(5):
p.submit(long_time_task, i)
p.shutdown(wait=True)
print('Finish')
if __name__ == '__main__':
# test_pool()
test_future_process()
output
Parent process 29368.
Run task 0 (32148)...
Run task 1 (31552)...
Run task 2 (24012)...
Run task 3 (29408)...
Task 2 runs 0.52 seconds.
Run task 4 (24012)...
Task 3 runs 0.86 seconds.
Task 1 runs 1.81 seconds.
Task 0 runs 1.83 seconds.
Task 4 runs 1.69 seconds.
Finish
多線程
def sayhello(a):
print("hello: " + a)
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (a, (end - start)))
def test_future_thread():
seed = ["a", "b", "c", "d"]
start = time.time()
with ThreadPoolExecutor(3) as executor:
for i in seed:
executor.submit(sayhello, i)
end = time.time()
print("Thread Run Time: " + str(end - start))
output
hello: a
hello: b
hello: c
Task a runs 0.40 seconds.
hello: d
Task b runs 0.56 seconds.
Task d runs 1.70 seconds.
Task c runs 2.92 seconds.
Thread Run Time: 2.9195945262908936
可以看出,由於是創建了限制為3的線程池,所以只有三個任務在同時執行
def write(q):
print("write(%s), 父進程為(%s)" % (os.getpid(), os.getppid()))
for i in "Python":
print("Put %s to Queue" % i)
q.put(i)
def read(q):
print("read(%s), 父進程為(%s)" % (os.getpid(), os.getppid()))
for i in range(q.qsize()):
print("read 從 Queue 獲取到消息: %s" % q.get(True))
def test_commun():
print("(%s) start" % os.getpid())
q = Manager().Queue()
pw = Process(target=write, args=(q, ))
pr = Process(target=read, args=(q, ))
pw.start()
pr.start()
pw.join()
pr.terminate()
output
(23544) start
write(29856), 父進程為(23544)
Put P to Queue
Put y to Queue
Put t to Queue
Put h to Queue
Put o to Queue
Put n to Queue
read(25016), 父進程為(23544)
read 從 Queue 獲取到消息:P
read 從 Queue 獲取到消息:y
read 從 Queue 獲取到消息:t
read 從 Queue 獲取到消息:h
read 從 Queue 獲取到消息:o
read 從 Queue 獲取到消息:n
Python 的 multiprocessing 模塊包裝了底層的機制,提供了 Queue、Pipes 等多種方式來交換數據
進程鎖:是為了控制同一操作系統中多個進程訪問一個共享資源,只是因為程序的獨立性,各個進程是無法控制其他進程對資源的訪問的,但是可以使用本地系統的信號量控制。信號量(Semaphore),有時被稱為信號燈,是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被並發調用
線程鎖:當多個線程幾乎同時修改一個共享數據的時候,需要進行同步控制,線程同步能夠保證多個線程安全的訪問競爭資源(全局內容),最簡單的同步機制就是使用互斥鎖。某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為鎖定狀態,其他線程就能更改,直到該線程將資源狀態改為非鎖定狀態,也就是釋放資源,其他的線程才能再次鎖定資源。互斥鎖保證了每一次只有一個線程進入寫入操作。從而保證了多線程下數據的安全性
並行:多個 CPU 核心,不同的程序就分配給不同的 CPU 來運行。可以讓多個程序同時執行
並發:單個 CPU 核心,在一個時間切片裡一次只能運行一個程序,如果需要運行多個程序,則串行執行
ThreadLocal 叫做線程本地變量,ThreadLocal 在每一個變量中都會創建一個副本,每個線程都可以訪問自己內部的副本變量,對其他線程時不可見的,修改之後也不會影響到其他線程
域名解析是指將域名解析為 IP 地址。也有反向的“逆解析”,將 IP 通過 DNS 服務器查找到對應的域名地址
DNS 是域名系統 (Domain Name System),域名系統為因特網上的主機分配域名地址和 IP 地址。用戶使用域名地址,該系統就會自動把域名地址轉為 IP 地址
LVS 是 Linux Virtual Server 的簡寫,意即 Linux 虛擬服務器,是一個虛擬的服務器集群系統,即負載均衡服務器
LVS 工作模式分為 NAT 模式、TUN 模式、以及 DR 模式
Nginx 主要功能:1、反向代理 2、負載均衡 3、HTTP 服務器(包含動靜分離) 4、正向代理
正向代理:某些情況下,代理用戶去訪問服務器,需要手動設置代理服務器的 IP 和端口號
反向代理:是用來代理服務器的,代理要訪問的目標服務器。代理服務器接受請求,然後將請求轉發給內部網絡的服務器(集群化),並將從服務器上得到的結果返回給客戶端,此時代理服務器對外就表現為一個服務器
負載均衡服務器類似於 LVS HTTP 服務器類似於 Tomcat 等
HAProxy 提供高可用性、負載均衡,以及基於 TCP 和 HTTP 的應用程序代理。keepalived 是集群管理中保證集群高可用的一個服務軟件,其功能類似於 heartbeat,用來防止單點故障
RPC 是指遠程過程調用,也就是說兩台服務器 A,B,一個應用部署在 A 服務器上,想要調用 B 服務器上應用提供的函數/方法,由於不在一個內存空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的數據
浏覽器通過 DNS 服務器查找到域名對應的 IP 地址
浏覽器給 IP 對應的 web 服務器發送 HTTP 請求
web 服務器接收到 HTTP 請求後,返回響應給浏覽器
浏覽器接收到響應後渲染頁面
CDN 的全稱是 Content Delivery Network,即內容分發網絡。CDN 是構建在網絡之上的內容分發網絡,依靠部署在各地的邊緣服務器,通過中心平台的負載均衡、內容分發、調度等功能模塊,使用戶就近獲取所需內容,降低網絡擁塞,提高用戶訪問響應速度和命中率。CDN 的關鍵技術主要有內容存儲和分發技術