網絡編程與並發編程總結

  • 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