網絡編程與並發編程總結
- 2019 年 12 月 16 日
- 筆記
軟件開發架構:
C/S架構:
Client:客戶端
Server:服務端
優點:佔用網絡資源少,軟件的使用更加穩定。
缺點:服務端更新後,客戶端也得跟着更新,訪問多個服務端需要下載對應的軟件,佔用客戶端計算機的硬件資源大。
B/S架構:
Browser:瀏覽器
Server:服務端
服務端:24小時不間斷提供服務
客戶端:訪問不同的服務端只需要在瀏覽器輸入不同的網址,佔用客戶端的硬件資源少,但是佔用網絡資源大,網速比較慢時會不穩定。
一、網絡編程:
1.互聯網協議OSI七層協議
- 應用層
- 表示層
- 會話層
- 傳輸層
- 網絡層
- 數據鏈路層
- 物理連接層 記憶:應表會傳網數物
-物理連接層
基於電信號發送二進制數據
-數據鏈路層
1)規定好電信號的分組方式
2)必須要有一塊網卡:
-mac地址:
12位唯一的16進制字符串:前六位為廠商號,後六位為流水號
-以太網協議:
在同一個局域網內通信:
單播:1對1吼
廣播:多對多吼(會出現廣播風暴)
不能跨局域網通信。
-網絡層
ip:定位局域網的位置
port:唯一標識一台計算機上一個應用程序。
arp協議:將mac地址獲取並解析成ip和port。
-傳輸層 TCP,特點:TCP協議稱為流式協議,若想要通信,必須建立連接
#### 1.1 TCP協議的三次握手:
客戶端往服務端發送建立連接請求,服務端回復收到請求同時發送服務端與客戶端建立連接的請求,客戶端回復收到建立連接的請求,雙向通道建立完成。
#### 12. TCP協議的四次揮手:
服務端向客戶端發送斷開連接請求,客戶端回復收到請求,然後檢測自己是否有數據在給客戶端發送,如果沒有則向客戶端發送斷開連接請求,客戶端回復同意斷開連接信息,客戶端與服務端斷開連接。
雙向通道反饋機制:客戶端向服務端發送獲取數據請求,客戶端發送確認收到的消息,如果服務端沒有返回消息,客戶端則會繼續隔段時間發送一次請求,如果時間過長仍沒有收到回復則停止發送請求。
1.2 UDP協議
特點:
- 數據不安全
- 不需要建立雙向通道
- 客戶端發送數據給服務端不需要收到服務端的確認消息
- 傳輸速度快
- 不會有粘包問題
TCP與UDP的區別:
TCP:如同是在打電話
UDP:如同是在發短訊
應用層
ftp
http
http+ssl
2.socket
socket用來寫套接字客戶端與服務端,內部幫我們封裝好了7層協議需要做的事情。
3.手擼socket套接字模板
3.1 服務端
import socket
server = socket.socket()
server.bind(('127.0.0.1',6666))括號內是ip和端口號,且是元組的形式
server.listen(6)半連接池
conn,addr = server.accept()
data = conn.recv(1024)接收數據的二進制位長度
conn.send('發送的消息'.decode('utf-8'))
3.2 客戶端
import socket
client = socket.socket()
client.connect(('ip',port))
client.send()
client.recv(1024)
4.subprocess(了解)
功能:通過代碼往cmd創建一個管道,並且發送命令和接收cmd返回的結果。
用法:
import subprocess
obj = subprocess.Ponpen('cmd命令',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
success = obj.stdout
error = obj.stderr.read()
msg = success + error
5.粘包問題
1)不能確定對方發送數據的大小
2)在短時間內,間隔時間短,並且數據量小的情況下,默認將這些數據打包成一個,多次發送的數據一次性發送。
6.struct解決粘包問題
初級版:
將一個數據的長度打包成一個固定長度的報頭,struck.pack('i',len(data))
對方獲取數據時用
data = struct.unpack('i',headers)[0]
注意:以什麼方式打包必須以什麼方式解包
升級版:
先將數據存放到字典中,將字典打包發送過去:好處,真實數據長度,文件的描述信息,發送的數據更小。
dic = {
'data_len':10000,
文件的描述信息
}
7.上傳大文件數據
客戶端
dic = {
文件大小
文件名
}
with open(文件名,『rb')as f:
for line in f:
client.send(line)
服務端
dic = {
文件大小
文件名
}
init_recv = 0
with open(文件名,』wb') as f:
while init_recv<文件大小:
data = conn.recv(1024)
f.write(dara)
init_recv += len(data)
8.socketserver(現階段,了解)
可支持並發
import socketserver
定義類
TCP:必須繼承BaseRequestHandler類
class MyTcpServer(socketserver.BaseRequestHandler)
-handle
內部實現了server = socket.socket()
server.bind(('127.0.0.1',6666))
server.listen(5)
while True:
conn,addr = server.accept()
print(addr)
必須重寫父類的handle。當客戶端連接時會調用該方法
def handle(self):
print(self.client_address)
while True:
request.recv(1024)
self.request.send()
TCP:
SOCK_STREAM
conn.recv
UDP:
SOCK_DGRAM
server.refrom()
8.1 UDP套接字模板:
服務端:
import socket
server= socket.socket(type=socket_SOCK_DGRAM)
server.bind((ip,port))
data,addr = server.refrom(1024)
客戶端
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (ip,port)
client.sendto(data,ip_port)
data,_ = client.refrom(1024)
print(data)
二、並發編程
多道技術
多道:切換+保存狀態
-空間上的復用:支持多個程序使用
-時間上的復用:遇到IO操作就會切換程序,程序佔用CPU時間過長也會被切換。
1.並發與並行:
並發:看起來像同時運行:多道技術 並行:真正意義上的同時運行:多核下 進程: 進程是資源單位,每創建一個進程都會生成一個名稱空間,佔用內存資源。 程序就是一堆代碼 進程就是一堆代碼運行的過程
2.進程調度:
時間片輪轉法: 10個進程,將固定時間等分成10等份,分配給每個進程
分級別反饋隊列 時間短的,執行權限最高放在一級隊列,時間長一點的放下面 1級別: 2級別: 3級別:
3.進程的三個狀態:
就緒態:創建多個進程,排隊準備運行 運行態:進程開始運行,結束、阻塞 阻塞態:遇到IO操作進入,阻塞態之後進入就緒態 佔用CPU時間過長會進入就緒態
4.同步與異步:
同步異步是提交任務的方式,同步指同步提交,是串行的,一個任務結束另一個任務才能提交執行;異步指異步提交,多個任務可以並發運行
5.阻塞與非阻塞
阻塞:阻塞態 非阻塞:就緒態、運行態
同步和異步,阻塞和非阻塞是不同的概念不能混為一談。 等待不一定是阻塞,有可能某個任務佔用CPU的時間過長, 所以他們不是同一個概念。
最大化提高CPU的使用率:儘可能減少不必要的IO操作
### 6.創建進程的兩種方式 1. p = Process() p.start()向操作系統提交創建進程的任務 p.join() p.daemon = True 必須放在start()前面,否則報錯 2. class MyProcess(Process): def run(self):
任務的過程
p = MyProcess()
p.daemon = True 必須放在start()前,否則報錯
p.start()
p.join()
7.回收進程的兩種條件:
1.調用join讓子進程結束後子進程結束 2.主進程正常結束
### 8.殭屍進程與孤兒進程 殭屍進程:凡是子進程結束後pid號還存在的進程 父進程已經結束
孤兒進程:主進程已經結束,子進程還在運行
守護進程:只要主進程結束,所有添加守護進程的子進程都必須結束
9.互斥鎖:
保證數據安全 from multiprocessing import Lock mutex = Lock() mutex = acquire() mutex = release()
10.隊列
from multiprocessing import Queue q = Queue(5) q.put() q.put_nowait() q.get() q.get_nowait()
堆棧:LIFO
10.1 IPC進程間通信
進程間的數據是隔離的 隊列可以讓進程間通信 把一個程序放入隊列中,另一個程序從隊列中獲取,實現進程間的數據交互。
10.2 生產者與消費者模型
生產者:生產數據 消費者:使用數據
為了保證平衡:通過隊列實現 生產者將數據扔進隊列中,消費者從數據中去數據
11.線程
11.1 什麼是線程
進程是資源單位 線程是執行單位
創建進程時會自帶一個線程(主線程)
11.2進程與線程的優缺點
進程: 優點:多核下計算密集型程序 缺點:開銷資源高於線程
線程;優點:佔用資源小 IO密集下,提高效率 缺點:無法使用多核優勢
線程間數據是共享的
12.全局解釋器鎖
在CPython中,全局解釋器鎖(即GIL)是一個互斥鎖,可以防止一個進程中的多個線程同時(並行)執行。 鎖定是必要的,主要是因為CPython的內存管理不是線程安全的。GIL的存在就是為了保證線程安全。
### 13.死鎖現象
所謂死鎖:是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程
14.遞歸鎖
解決死鎖現象 mutex1,mutex2 = RLock() 只有這把鎖的計數為零才會被下一個人使用
15.信號量
也是一把鎖,可以讓多個人,多個用戶一起使用 sm = Semaphore(5)
16.線程隊列:保證線程間數據的安全
import queue FIFO:先進先出隊列 queue.Queue()
LIFO:後進先出隊列 queue.LifoQueue() 優先級隊列 queue.PriorityQueue()
17.event事件
可以控制線程的執行,讓一些線程控制另一些線程的執行
線程池與進程池 為了控制進程、線程的創建的數量,保證了硬件能正常運行。
from concurrent.futures import ProcessPoolExecutor,TreadPoolExecutor
pool1 = ProssPoolExecutor()默認是CPU的個數
pool2 = ThreadPoolExecutor()默認是CPU個數*5
18.回調函數
pool.submit(函數名,參數).add_done_callback(回調函數名)
注意:回調函數必須接收一個參數,且這個參數是第一個函數的返回值。
res1 = res.result() 獲取返回值。
19.協程
協程:單線程下實現並發,不是任何的單位,是程序員YY出來的名字。
協程的優點:節省內存資源,進一步提高CPU的利用率(只有在IO密集型程序中才有優點)
高並發:多進程+多線程+協程
19.1 協程的手動創建:
手動實現切換+保存狀態:
yield+next:yield對程序的暫停不會被操作系統識別為IO操作
19.2 使用gevent實現單線程下的並發
from gevent import monkey
monkey,patch_all()監聽是否有IO操作
from gevent import spawn,joinall 實現切換+保存狀態
s1 = spawn(任務1)
s2 = spawn(任務2)監聽是否有IO操作
joinall([s1,s2])等待所有的程序執行完畢結束,執行下面的程序。
20.IO模型(了解)
阻塞IO
非阻塞IO
多路復用IO
異步IO