目錄python
C/S: Client: 客戶端 Server: 服務端 優勢: 佔用網絡資源少,軟件的使用穩定 缺點: 服務端更新後,客戶端也得跟着跟新. 須要使用多個軟件,須要下載多個客戶端 B/S: Browser: 瀏覽器(客戶端) Server: 服務端 服務端與客戶端做用: 服務端: 24小時不間斷提供服務 客戶端: 須要體驗服務端時,再去鏈接服務端,並享受服務
一 網絡編程:
1.互聯網協議OSI七層協議
1)應用層
2)表示層
3)會話層
4)傳輸層
5)網絡層
6)數據鏈路層
7)物理鏈接層程序員
- 物理鏈接層 基於電信號發送二進制數據. - 數據鏈路層 1) 規定好電信號的分組方式 2) 必需要有一塊網卡: - mac地址: 12位惟一的16進制字符串 - 前6位: 廠商號 - 後6位: 流水號 - 以太網協議: 在同一個局域網內通訊. - 單播 1對1吼 - 廣播 多對多吼 - 廣播風暴: - 不能跨局域網通訊 - 網絡層 - ip: 定位局域網的位置 - port: 惟一標識一臺計算機上一個應用程序. - arp協議: 將mac地址獲取,並解析成ip和port. - 傳輸層 - TCP 特色: TCP協議稱之爲流式協議. 若想要通訊,必須創建鏈接,並創建雙向通道. - 三次握手,四次揮手 - 三次握手建鏈接 - 客戶端往服務端發送請求創建通道 - 服務端要確認客戶端的請求,並往客戶端也發送請求創建通道 - 客戶端接收到服務端創建鏈接的請求,並返回確認 - 創建雙向通道 - 雙向通道: - 反饋機制 客戶端往服務端發送請求獲取數據,服務端務必返回數據,客戶端確認收到. 反則會反覆發送,一直到某個時間段內,會中止發送 - 四次揮手斷鏈接 - C往S發送斷開鏈接請求,S返回確認收到 - S須要再次發送斷開鏈接請求 - C返回確認收到 - 最終確認斷開鏈接 - UDP 1)數據不安全 2)不須要創建雙向通道 3)傳輸速度快 4)不會有粘包問題 5)客戶端發送數據,不須要服務端確認收到,愛收不收 TCP與UPD的區別: TCP: 比喻成在打電話 UDP: 比喻成發送短信 - 應用層 - ftp - http: 能夠攜帶一堆數據 - http + ssl 2.socket socket用來寫套接字客戶端與服務端的模塊,內部幫咱們封裝好了7層協議須要作的事情. 3.手擼socket套接字模板 - 服務端: import socket server = socket.socket() server.bind( (ip, port) ) # 綁定手機號 server.listen(6) # 半鏈接池: 能夠接待7個客戶端 # 監聽鏈接 conn, addr =server.accept() # 接收消息 data = conn.recv(1024) # 發送消息 conn.send('消息內容'.encode('utf-8')) - 客戶端: import socket client = socket.socket() client.connect( (ip, port) ) # 發送消息 client.send() # 接收消息 client.recv(1024) 4.subprocess(瞭解) 用來經過代碼往cmd建立一個管道,而且發送命令和接收cmd返回的結果. import subprocess obj = subprocess.Popen( 'cmd命令', shell=True, # 接收正確結果 stdout=subprocess.PIPE, # 接收錯誤結果 stderr=subprocess.PIPE ) success = obj.stdout.read() error = obj.stderr.read() msg = success + error 5.黏包問題 1.不能肯定對方發送數據的大小 2.在短期內,間隔時間短,而且數據量小的狀況, 默認將這些數據打包成一個 屢次發送的數據 ---> 一次性發送 6.struct解決黏包問題 初級版: i: 4 能夠將一個數據的長度打包成一個固定長度的報頭. struct.pack('模式i', '源數據長度') data = 'gagawagwaga' # 打包成報頭 headers = struct.pack('i', len(data)) # 解包獲取數據真實長度 data = struct.unpack('i', headers)[0] 注意: 以什麼方式打包,必須以什麼方式解包. 升級版: 先將數據存放到字典中,將字典打包發送過去 - 字典的好處: - 真實數據長度 - 文件的描述信息 - 發送的數據,更小 dic = { 'data_len': 1000000000000000000000046546544444444444444444444444444444444444444, 文件的描述信息 } 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(data) init_recv += len(data) 10.socketserver(現階段,瞭解) - 能夠支持併發 import socketserver # 定義類 # TCP: 必須繼承BaseRequestHandler類 class MyTcpServer(socketserver.BaseRequestHandler): - handle # 內部實現了 server = socket.socket() server.bind( ('127.0.0.1', 9527) ) server.listen(5) --- while True: conn, addr = server.accept() print(addr) # 必須重寫父類的handle, 當客戶端鏈接時會調用該方法 def handle(self): print(self.client_address) while True: try: # 1.接收消息 # request.recv(1024) == conn.recv(1024) data = self.request.recv(1024).decode('utf-8') send_msg = data.upper() self.request.send(send_msg.encode('utf-8')) except Exception as e: print(e) break TCP: SOCK_STREAM conn.recv() UDP模板: SOCK_DGRAM server.recvfrom() - 服務端 import socket server = socket.socket( type=socket.SOCK_DGRAM ) server.bind( (ip, port) ) data, addr = server.recvfrom(1024) server.sendto(data, addr) - 客戶端 import socket client = socket.socket( type=socket.SOCK_DGRAM ) ip_port = (ip, port) client.sendto(data, ip_port) data, _ = client.recvfrom(1024) print(data)
二 併發編程
12.多道技術
- 單道shell
- 多道: 切換 + 保存狀態 - 空間上的複用 支持多個程序使用 - 時間上的複用 - 遇到IO操做就會切換程序 - 程序佔用CPU時間過長切換 13.併發與並行 併發: 看起來像同時運行: 多道技術 並行: 真正意義上的同時運行: 多核下 14.進程 進程是資源單位,沒建立一個進程都會生成一個名稱空間,佔用內存資源. - 程序與進程 程序就是一堆代碼 進程就是一堆代碼運行的過程 - 進程調度 - 時間片輪轉法 10個進程, 將固定時間,等分紅10份時間片,分配給每個進程. - 分級反饋隊列 1級別: 2級別: 3級別: - 進程的三個狀態 - 就緒態: 建立多個進程, 必需要排隊準備運行 - 運行態: 進程開始運行, 1.結束 2.阻塞 - 阻塞態: 當運行態遇到IO操做,就會進阻塞態. - 同步與異步 提交任務的方式 - 同步: 同步提交, 串行,一個任務結束後,另外一個任務才能提交併執行. - 異步: 異步提交, 多個任務能夠併發運行 - 阻塞與非阻塞 - 阻塞: 阻塞態 - 非阻塞: 就緒態 運行態 - 同步和異步、阻塞和非阻塞的區別。 二者是不一樣的概念,不能混爲一談. - 建立進程的兩種方式 一: p = Process(target=任務, args=(任務的參數, )) p.daemon = True # 必須放在start()前,不然報錯 p.start() # 向操做系統提交建立進程的任務 p.join() # 向操做系統發送請求, 等全部子進程結束,父進程再結束 二: class MyProcess(Process): def run(self): # self == p 任務的過程 p = MyProcess() p.daemon = True # 必須放在start()前,不然報錯 p.start() # 向操做系統提交建立進程的任務 p.join() # 向操做系統發送請求, 等全部子進程結束,父進程再結束 - 回收進程資源的兩種條件 - 調用join讓子結束後,主進程才能結束. - 主進程正常結束 15.殭屍進程與孤兒進程(瞭解) 殭屍進程: 凡是子進程結束後,PID號還在, 主進程意外死亡,無法給子進程回收資源. - 每一個子進程結束後,都會變成,殭屍進程 (PID) 孤兒進程: 凡是子進程沒有結束,可是主進程意外死亡.操做系統優化機制(孤兒院), 會將沒有主,而且存活的進程,在該進程結束後回收資源. 16.守護進程 只要父進程結束,全部的子進程都必須結束. 17.互斥鎖 將併發變成串行,犧牲執行效率,保證數據安全. from multiprocessing import Lock mutex = Lock() # 加鎖 mutex.acquire() 修改數據 mutex.release() 18.隊列 - FIFO隊列: 先進先出 from multiprocessing import Queue q = Queue(5) # 添加數據,若隊列添加數據滿了,則等待 q.put() # 添加數據,若隊列添加數據滿了,直接報錯 q.put_nowait() # 獲取隊列中的數據 q.get() # 若隊列中沒數據,會卡住等待 q.get_nowait() # 若隊列中沒數據,會直接報錯 19.堆棧 LIFO 20.IPC進程間通訊 - 進程間的數據是隔離的 - 隊列可讓進程間通訊 - 把一個程序放入隊列中,另外一個程序從隊列中獲取,實現進程間數據交互 21.生產者與消費者 模型 生產者: 生產數據 消費者: 使用數據 爲了保證 供需平衡. 經過隊列實現, 生產者將數據扔進隊列中,消費者從隊列中獲取數據. 能夠保證一邊生產一邊消費. 22.線程 - 什麼是線程 - 進程: 資源單位 - 線程: 執行單位 - 建立進程時,會自帶一個線程 一個進程下能夠建立多個線程. - 使用線程的好處 節省資源的開銷 - 進程與線程優缺點: - 進程: 優勢: - 多核下能夠並行執行 - 計算密集型下提升效率 缺點: - 開銷資源遠高於線程 - 線程: 優勢: - 佔用資源遠比進程小 - IO密集型下提升效率 缺點: - 沒法利用多核優點 23.線程間數據是共享的 - 畫圖 24.GIL全局解釋器鎖 - 只有Cpython纔有自帶一個GIL全局解釋器鎖 1.GIL本質上是一個互斥鎖. 2.GIL的爲了阻止同一個進程內多個線程同時執行(並行) - 單個進程下的多個線程沒法實現並行,但能實現併發 3.這把鎖主要是由於CPython的內存管理不是 "線程安全" 的. - 內存管理 - 垃圾回收機制 注意: 多個線程過來執行,一旦遇到IO操做,就會立馬釋放GIL解釋器鎖,交給下一個先進來的線程. 總結: GIL的存在就是爲了保證線程安全的,保證數據安全 25.多線程使用的好處 - 多線程: IO密集型,提升效率 - 多進程 計算密集型,提升效率 26.死鎖現象(瞭解) 27.遞歸鎖(瞭解,之後不用) 解決死鎖現象 mutex = Lock() # 只能引用1次 mutex1, mutex2 = RLock() # 能夠引用屢次 +1, 只要這把鎖計數爲0釋放該鎖, 讓下一我的使用, 就不會出現死鎖現象. 28.信號量(絕對了解) 信號量也是一把鎖, 可讓多個任務一塊兒使用. 互斥鎖: 只能讓一個任務使用 信號量: 可讓多個任務一塊兒使用. sm = Semaphore(5) 可讓5個任務使用 29.線程隊列 使用場景: 若線程間數據不安全狀況下使用線程隊列, 爲了保證線程間數據的安全. import queue - FIFO: 先進先出隊列 queue.Queue() - LIFO: 後進先出隊列 queue.LifoQueue() - 優先級隊列: - 根據數字大小判斷,判斷出隊優先級. - 進隊數據是無序的 queue.PriorityQueue() 30.event事件 能夠控制線程的執行,讓一些線程控制另外一些線程的執行. e = Event() - 線程1 e.set() # 給線程2發送信號,讓他執行 - 線程2 e.wait() # 等待線程1的信號 31.進程池與線程池 爲了控制進程/線程建立的數量,保證了硬件能正常運行. from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor pool1 = ProcessPoolExecutor() # 默認CPU個數 pool2 = ThreadPoolExecutor() # CPU個數 * 5 pool3 = ProcessPoolExecutor(100) # 100個 pool4 = ThreadPoolExecutor(200) # 200個 # 將函數地址的執行結果,給回調函數 pool4.submit(函數地址, 參數).add_done_callback(回調函數地址) - 回調函數(必須接收一個參數res): # 獲取值 res2 = res.result() 32.協程 - 進程: 資源單位 - 線程: 執行單位 - 協程: 單線程下實現併發, 不是任何的單位,是程序員YY出來的名字. - 單線程下實現併發 好處是節省資源, 單線程 < 多線程 < 多進程 - IO密集型下: 協程有優點 - 計算密集型下: 進程有優點 - 高併發: - 多進程 + 多線程 + 協程 (Nginx) 協程的建立: 手動實現切換 + 保存狀態: - yield - 函數一直在調用next() 會不停地切換 yield不能監聽IO操做的任務 - gevent來實現監聽IO操做 33.gevent pip3 install gevent from gevent import monkey monkey.patch_all() # 設置監聽全部IO from gevent import spawn, joinall # 實現 切換 + 保存狀態 - 實現了單線程下實現併發 s1 = spawn(任務1) s2 = spawn(任務2) joinall([s1, s2]) 34.IO模型(瞭解) - 阻塞IO - 非阻塞IO - 多路複用IO - 異步IO