網絡編程+併發編程 架構:B/S 和 C/S C/S:充分發揮PC機的性能 B/S:統一了應用的接口,隸屬於CS架構 OSI模型 七層:表示層,會話層,應用層,傳輸層,網絡層,數據鏈路層,物理層。 咱們用五層 應用層 http協議 https協議 ftp協議 snmp/pop3/stmp/dns 傳輸層 tcp udp 協議 (四層交換機) 網絡層 IP協議/icmp協議 路由器 (三層交換機) 數據鏈路層 arp協議,交換機 (二層交換機) 物理層 網卡,雙絞線 (傳輸電信號) arp/rarp Arp協議(地址解析協議):經過目標ip地址獲取目標mac地址 arp涉及到的物理設備:二層交換機 rarp:經過mac地址找ip地址 物理地址:mac地址全球惟一,每一個電腦的網卡上 Ip地址: 四位點分十進制 三十二位點分二進制ipv4/ipv6 : 4位點分十進制,6爲冒分16進制 交換機的通訊方式: 單播:點對點 組播:點對多 廣播:向多個pc端發送數據包 交換機和路由器的區別? 交換機是組織局域網的,通過內部處理解析數據,將數據已點對點,點對多的方式發送給目標 路由器是跨網段的數據傳輸,路由出網絡傳輸的最佳路徑 socket 介於應用層和傳輸層的socket抽象層 Tcp: 可靠、面向鏈接的雙全工通訊 無邊界的字節流 慢 佔用系統中的鏈接資源 1 全雙工的 面向字節流的(無邊界的字節流,多條tcp數據之間沒有邊界) 2 可靠,不是不安全,更多的是保證數據的網址性 3 (面相連接,必需要先創建鏈接再進行同窗)三次握手,四次揮手 4 慢:通訊 創建/斷開鏈接 保證數據的完整性的機制 5 佔用系統資源(核心要解決的問題) 在不使用任何異步機制(進程/線程/協程),在阻塞io模型中,一個server端只能和一個client端相連 conn1,conn2,conn3 sk = socket.socket() sk.setblocking(False) # 異步的概念 conn_lst = [] try: conn,addr = sk.accept() conn_lst.append(conn) except BlockingIOError: for conn in conn_lst: try: conn1.recv() # 有數據在緩存裏面就接收,沒有數據就報錯 except BlockingIOError:pass Udp: 無鏈接的,面向數據報,面向數據報的,不可靠,速度快,能傳輸的數據長度有限。能夠同時和多個客戶端通訊 不會粘包、速度快、能夠和任意多個客戶端進行互相通訊 容易丟失數據、傳輸的數據長度有限 三次握手:(必須是客戶點先發起) 1.客戶端發起SYN請求連接服務端 2.服務端收到請求,向客戶端發送能夠鏈接的請求 ACK 3.客服端收到鏈接,鏈接成功 ACK 四次揮手:(客戶端和服務端均可以發起) 1.客戶端發起斷開鏈接的FIN請求 2.服務端收到請求,而後準備斷開鏈接的一些事物 3.服務端發送請求,我已經準備完畢,能夠斷開了 4.客戶端收到請求,斷開鏈接。 爲何揮手是四次? 當我仍然有數據發送的時候,還能夠發送! 爲何會發生黏包:由於有緩存機制,連續發或者連續收。(在數據傳輸過程當中,接收數據端接收數據時不知道該如何接收,形成的數據混亂現象) 合包機制:nagle算法 — 發數據的時候一點一點發,可是接收的時候會一次收到。 拆包機制:發送的數據太大,分開發送,接收的時候,最後不能剛剛接完,就會發生黏包。 都是發生在發送端。 全部的數據都會在接收端的緩存區中被合在一塊兒,若是沒有及時獲取信息,那麼消息會粘在一塊兒。 發生在接收端 如何解決黏包? 自定義表頭:用struct模塊,事先將要發送文件的大小存下來,發送 過去,而後按着指定數據開始接收。 Struct 模塊 能夠將一個整數,封裝爲一個指定(通常爲4)字節數的數字,這樣接收端就能夠指定大小接收這個數字。 各類網絡設備 傳輸層 四次防火牆/四層防火牆/四層交換機 網絡層 路由器 防火牆 三層交換機 數據鏈路層 交換機 網卡 物理層 網線 socketserver(threading/socket/selector) 幫助你完成server端的併發效果模塊socket在應用層和傳輸層之間,socket是一組封裝了後四層協議數據拼接的接口。 操做系統 Dos系統 #單用戶單任務 Windows系統 #單用戶多任務(早起的Windows) Unix系統 #多用戶多任務 操做系統的做用:1)封裝接口,讓用戶方便使用 2)對系統資源的分配與調度 計算機的五大組成部分:運算器。控制器。存儲器。輸入設備。輸出設備。 編程語言發展史:機器語言,彙編語言,高級語言 並行:(兩件事或者多件事)同一時間點,同時執行 (多個CPU) 併發:(兩件事或者多件事)同一時間間隔,交替執行 阻塞:程序由於相似IO等待、等待時間等致使沒法繼續執行 非阻塞:程序遇到相似於IO操做時,再也不阻塞等待,若是沒有及時的處理IO,就會報錯或者跳過等待其餘操做, 同步:某一個任務的執行必須依賴另外一個任務的返回結果 -任務(當前所在的代碼和另外一個獨立的任務) 異步:一個任務的執行,不須要依賴另外一個任務的返回,只須要告訴另外一個任務一聲 ### p.start() 只是向操做系統發了一個啓動的命令,至於操做系統何時啓動我無論,這就是一個典型的異步非阻塞 進程:cpu資源分配的最小單位 進程由三部分組成:代碼段,數據段,PCB(進程控制塊) 資源獨立,能利用多核,佔用操做系統的資源大,有數據安全問題 線程:cpu資源調度的最小單位 線程由三部分組成:代碼段,數據段,TCB(線程控制塊) 資源共享,能利用多核,佔用操做系統的資源相對少,有數據安全問題 協程:操做系統不可見 資源共享,不能利用多核,本質是一條線程,佔用操做系統的資源就 至關於一條線程,不存在數據安全問題進程: 資源獨立線程 處理併發 (同時處理多個任務)GIL鎖 CPython解釋器中管理線程的機制 保證多個線程,只有一個線程在同一時間點能訪問cpu CPython解釋器致使了咱們不能充分利用多線程來訪問多個cpu 多進程:幫助咱們Cpython解釋器下利用多核協程 在單線程中,有n個任務,這n個任務若是是同步執行,那麼全部的io時間是累加在一塊兒的 若是這n個任務可以共享全部的io時間 完成一個任務,遇到io以後可以切換到另外一個任務執行,全部的io操做的時間還能作其餘任務的執行 這樣就能經過一條線程完成多個任務。 協程:切換也是有開銷的,切換的開銷就和函數調用的開銷是同樣的。 asyncio 內置的異步模塊 (進程、線程、協程) gevent 擴展的協程模塊 aiohttp 擴展模塊 幫助咱們利用協程完成http請求的模塊數據安全 多個進程操做一個文件,加鎖 多個線程操做一個全局變量,加鎖 若是是+= *= /= -= 都存在數據不安全的問題 append remove pop extend 不存在數據不安全的問題 協程 永遠不會數據不安全,由於協程是由程序員控制的,而程序員控制的只能是代碼,而不是CPU指令 import dis dis.dis() # 查看CPU指令 進程的三大基本狀態: 就緒狀態:已經得到運行所需的全部資源,除CPU 執行狀態:已經得到全部資源包括CPU,處於正在運行 阻塞狀態:由於各類緣由,進程放棄了CPU,致使進程沒法繼續執行,此時進程處於內存中,繼續等待獲取CPU的一種狀態。ß 進程學的東西: multiprocessing 1)Process模塊 線程的建立 1)直接建立 p = Process(target = func, args = (元組形式, 爲func所傳的參數)) #實例化進程對象 2)繼承 (Process) 多線程的開啓 1)for循環 2)多個對象實例化 方法: start() #開啓進程 join() #感知進程的結束,異步變同步 is_alive() #判斷進程是否存活 terminate() #殺死一個進程 屬性: name #獲取進程名 pid #獲取進程號 daemon = True #守護進程 守護進程的特色: #當主進程代碼結束後,守護進程隨主進程結束 #守護進程不能再建立子進程 #守護進程必須在start以前 2) 鎖 Lock模塊 (互斥鎖/同步鎖) 只能acquire一次 lock = Lock() #實例化一個鎖對象 lock.acquire() #上鎖 lock.release() #解鎖 RLock模塊 (遞歸鎖) 遞歸鎖能夠同時acquire屢次,可是必須acquire幾回就必須release幾回。都在就會陷入死鎖狀態 死鎖 典型的例子:科學家吃麪 (一我的拿着面,一我的拿着叉子,到最後誰也吃不上面) 信號量 Semaphore模塊 sem = Semaphore(int數據類型) #能夠指定有多少線程能夠同時拿到鎖 sem.acquire() #須要上鎖將這些數據鎖住 sem.release() 事件 Event模塊 e = Event() e.wait() #根據is_set()的狀態來決定,自身的阻塞狀態 若是is_set()爲False則爲阻塞,若是is_set()爲True則爲非阻塞 e.is_set() #默認爲False, e.set() #將is_set()的狀態變爲True e.clear() #將is_set()的狀態變爲False 典型例子:紅綠燈事件 3)進程間通訊(IPC) Queue模塊 #隊列 先進先出 First in first out q = Queue() #建立隊列對象(能夠指定大小) q.put() #向隊列中添加元素(若是隊列以滿處於阻塞狀態,只有當隊列不滿才能夠繼續添加) q.get() #取出隊列中元素(若是隊列中元素爲空處於阻塞狀態,只有對列中有元素才能夠繼續取出) q.full() #判斷一個對列是否 已滿 q.empty() #判斷一個對列是否爲空 q.put_nowait() #不阻塞,若是能夠繼續往隊列中放數據就繼續放,不能放就報錯 q.get_nowait() #不阻塞,若是有數據就直接獲取,沒有數據就報錯 JoinableQueue()模塊 q = JoinableQueue() #繼承了Queue模塊,可是新增了兩個方法 q.task_done() #統計對列q有多少個元素被拿走(拿走一個數據就給join返回一個結果),一般與q.get()在一塊兒用 用於生產者 q.join() #感知一個對列的數據被所有執行完畢 與q.put()在一塊兒用 用於消費着 隊列 = 管道 + 鎖 重點:生產者消費着模型 應用場景:爬蟲/高併發的web程序server Pipe模塊 #管道 (自己是不安全的) (雙全工) p = Pipe() conn1, conn2 = Pipe() 管道是不安全的 管道是用於多進程之間通訊的一種方式 若是在單進程中使用管道,那麼就是conn1收數據,conn2發數據 若是是conn1發數據,那麼conn2收數據 若是在多進程中使用管道,那麼就必須是父進程中用con1收,子進程中使用conn2發 父進程使用conn1發,子進程中使用conn2收 父進程使用conn2收,子進程中使用conn1發 父進程使用conn2發,子進程中使用conn1收 在管道中有一個著名的錯誤叫作EOFERrror。 是指:父進程中若是關閉了發送端,子進程還繼續接受數據,那麼就會引起EOFError 4)數據共享 Manager模塊 Value模塊 men = Manager() (1) m.list(列表數據) m.dict(字典數據) (2) with Manager() as m: …… 5)進程池 Pool模塊 p = Pool(os.cup_count() +1) #開啓多進程以後,每次處理數據只能指定個數個處理 p.close() p.join() #close在join以前 方法: map(func, itreable) #異步處理 itreable ,有返回值,返回值是,每個func的返回值組成的列表, 自帶close和join apply(func, args) #同步處理 有返回值,返回值爲func的返回值 不須要加close和join apply_async(func, args, callback) #異步處理,有返回值,返回一個對象,這個對象有get方法,能夠獲取func的返回值 #這個get只能一個一個獲取,以咱們通常處理完全部線程後再獲取數據 #func的返回值能夠做爲參數傳給callback這個回調函數。回調函數在主進程中執行 apply函數中的全部進程都爲普通進程 apply_async函數中的全部進程都爲守護進程 線程學的東西:threading GIL:全局解釋器鎖(只有CPython纔有) 鎖的是線程:同一時間只容許一個線程訪問CPU #(沒有真正的並行) 1)Thread模塊 線程的建立 1)t = Thresd(target= func. args = (元組,爲func所傳的參數)) 實例化線程對象 2)繼承 多線程的建立 1)for 循環 2)直接實例化多個對象 2) 鎖 Lock #互斥鎖(同步鎖) RLock #遞歸鎖 死鎖 #死鎖 信號量 Semaphore模塊 sem = Semaphore(int數據類型) #能夠指定有多少線程能夠同時拿到鎖 sem.acquire() #須要上鎖將這些數據鎖住 sem.release() 事件 Event模塊 e = Event() e.wait() #根據is_set()的狀態來決定,自身的阻塞狀態 若是is_set()爲False則爲阻塞,若是is_set()爲True則爲非阻塞 e.is_set() #默認爲False, e.set() #將is_set()的狀態變爲True e.clear() #將is_set()的狀態變爲False 3)條件 Condition模塊 條件是讓程序員自行去調度線程的一個機制 方法: acquire() release() wait() #讓線程阻塞住 notify(int數據類型) #是指給wait發一個信號,讓wait變成不阻塞 #int數據類型,是指你要給多少wai發信號 4)定時器 Timer模塊 建立:Timer(time, func) #time:睡眠時間,以秒爲單位 #func:睡眠以後,須要執行的任務 5)線程池 進程與線程的區別: 進程資源分配的基本單位,線程是cpu調度的基本單位。 線程不能夠本身獨立擁有資源。線程的執行,必須依賴於所屬進程中的資源。 進程中必須至少應該有一個線程。 線程和進程的比較: 1)cpu切換進程比切換線程慢不少,在python中若是IO操做過多的話,使用線程最好 2)在同一個進程內,全部線程共享這個進程pid,也就是說全部線程共享所屬進程的全部資源和內存地址 3)在同一個進程內,全部線程共享該進程中的全局變量 4)由於GIL鎖的存在,在CPython中,沒有真正的線程並行。可是有真正的多進程並行 當你的任務是計算密集的狀況下,使用多進程好。 總結:在CPython中,IO密集用多線程,計算密集用多線程。 5)關於守護線程和守護進程的事情:(注意:代碼執行結束,並不表明程序結束) 守護進程:要麼本身正常結束,要麼根據父進程的代碼執行結束而結束 守護線程:要麼本身正常結束,要麼根據父線程的執行結束而結束(會等其他子線程運行結束)