網路編程 一. 1.網卡: 電腦中有網卡,網卡中有mac地址. 2.IP: 插上網線,路由器或交換機中的DHCP服務會自動分配IP地址. IP:192.168.13.150 IPv4: 00000000.00000000.00000000.00000000 0-255 0-255 0-255 0-2 ...
網路編程
一.
1.網卡:
電腦中有網卡,網卡中有mac地址.
2.IP:
插上網線,路由器或交換機中的DHCP服務會自動分配IP地址.
IP:192.168.13.150
IPv4:
00000000.00000000.00000000.00000000
0-255 0-255 0-255 0-255
IPv6:
00000000.00000000.00000000.00000000.00000000.00000000
3.子網掩碼:255.255.255.0
IP:192.168.13.150
子網掩碼:255.255.255.0
4.網關:路由器中連接交換機的口
網關IP:第一個IP地址
5.DNS:
網路連接:
1.功能變數名稱解析:
Windows電腦:先去本地的hosts文件中找IP
C:Windows\System32\drivers\etc\hosts
Linux/Mac電腦:
/etc/hosts
2.連接:
sk = socket.socket()
sk.connect(("127.0.0.1",8000))
3.如果創業:
1.租一個伺服器+公網IP
2.租功能變數名稱:功能變數名稱+IP解析
總結:
IP:4個點分的十進位表示
DHCP:自動為區域網內中的電腦分配IP
網關:路由器中連接交換機的口
子網掩碼:將擋住的IP位數作為網段,未擋住的部分作為可變的值
IP:192.168.13.15.
子網掩碼:255.255.255.0
區域網,城域網,廣域網
arp協議:通過目標的IP地址,查找目標的mac地址
DNS
二.
1.OSI模型:
7層模型:
應用層:使用軟體
表示層:看到數據,如圖片,視頻
會話層:保持登錄或鏈接狀態
傳輸層:TCP/UDP
網路層:IP
數據鏈路層:MAC
物理層:將數據轉換成電信號發送
5層模型:
應用層:應用層,表示層,會話層
傳輸層
網路層
數據鏈路層
物理層
4層:
應用層:應用層,表示層,會話層
傳輸層
網路層
物理層L數據鏈路層,物理層
2.三次握手四次揮手
#三次握手:
1.客戶端(Client)向服務端(Server)發送一次請求
2.服務端確認並回覆客戶端
3.客戶端檢驗確認請求,建立連接
#四次揮手:
1.客戶端向服務端發一次請求
2.服務端回覆客戶端(斷開客戶端-->服務端)
3.服務端再次向客戶端發請求(告訴客戶端可以斷開了)
4.客戶端確認請求,連接斷開
斷開連接時,反映到代碼上就是拋出異常或發送空內容
三.
1.BS(Browser/Server)和CS(Client/Server)架構
BS:瀏覽器/伺服器
CS:客戶端/伺服器
a.CS架構是建立在區域網的基礎上的,BS架構是建立在廣域網的基礎上的
b.CS一般比BS安全
c.CS更加註重流程,BS更加註重訪問速度
d.BS比CS能更好的重用
e.CS比BS系統維護周期長,開銷大
f.CS多是建立在Windiws平臺上,BS建立在瀏覽器上.
四.
1.socket代碼:
1 import socket 2 服務端: 3 server = socket.socket() 4 server.bind(("127.0.0.1",8000)) 5 server.listen(5) 6 conn,addr = server.accept() 7 8 客戶端: 9 client = socket.socket() 10 client.connect(("127.0.0.1",8000))
2.黏包:
1.發送數據時,每次發送的包小,因為系統進行優化演算法,就將兩次的包放在一起發送,減少了資源的重覆占用,而客戶端接收時,會一次全部接收
2.接收數據時,多次接收,第一次接收的數據量小,導致數據還沒接收完,就停下了,剩下的數據會緩存在記憶體中,然後等到下次接收時和下一波數據一起接收.
解決方案:
1.先發送一個位元組總大小,然後接收端迴圈接收所有數據.
2.使用time模塊
3.先使用struct模塊發送4個位元組的文件大小,然後再發送數據.
3.協議:
自定義協議:{"code":1001,"data":{...}}
HTTP協議:GET /swd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n
併發編程
1.線程,進程,協程的區別:
2.進程:
1 import multiprocessing 2 3 def task(arg): 4 print(arg) 5 6 def run(): 7 p = multiprocessing.Process(target=task,args=(1,)) 8 p.start() 9 10 if __name__ == '__main__': 11 run()
獲取當前進程:name = multiprocessing.current_process()
進程間的數據共用:
1 1.Queue 2 3 import multiprocessing 4 5 q = multiprocessing.Queue() 6 7 def task(arg,q): 8 q.put(arg) 9 10 def run(): 11 for i in range(10): 12 p = multiprocessing.Process(target=task,args=(i,q)) 13 p.start() 14 15 while True: 16 v = q.get() 17 print(v) 18 19 2.Manager 20 21 import multiprocessing 22 23 def task(arg,dic): 24 dic[arg] = 100 25 26 if __name__ == '__main__': 27 m = multiprocessing.Manager() 28 dic = m.dict() 29 process_list = [] 30 31 for i in range(10): 32 p = multiprocessing.Process(target=taskargs=(i,dic)) 33 p.start() 34 process_list.append(p) 35 36 while True: 37 count = 0 38 for p in process_list: 39 if not p.is_alive(): 40 count += 1 41 if count == len(process_list): 42 break 43 print(dic)
進程鎖:
1 import time 2 import multiprocessing 3 4 lock = multiprocessing.RLock() 5 6 def task(arg): 7 print(111) 8 lock.acquire() 9 print(arg) 10 lock.release() 11 12 if __name__ == '__main__': 13 p1 = multiprocessing.Process(target=task,args=(1,)) 14 p1.start() 15 16 p2 = multiprocessing.Process(target=task,args=(2,)) 17 p2.start()
進程池
1 from concurrent.futures import ProcessPoolExcutor 2 3 def task(arg): 4 print(arg) 5 6 if __name__ == '__main__': 7 pool = ProcessPoolExcutor(5) 8 for i in range(10): 9 pool.submit(task,i)
3.線程
1 import threading 2 3 def task(arg): 4 print(arg) 5 6 for i in range(10): 7 t = threading.Thread(target=task,args=(i,)) 8 t.start() 9 10 獲取當前線程 11 ct = threading.current_thread() 12 13 獲取當前線程名字: 14 name = threading.getName()
線程鎖:
1 Lock:一次放一個,只能鎖一次 2 RLock:一次放一個,可以鎖多次 3 BoundedSemaphore(n):一次放n個 4 Condition:一次放指定個 5 Event:一次放所有 6 7 import threading 8 9 lock = threading.RLock() 10 11 def task(arg): 12 lock.acquire() 13 print(arg) 14 lock.release() 15 16 for i in range(10): 17 t = threading.Thread(target=task,args=(i,)) 18 t.start()
線程池
1 from concurrent.futures import ThreadPoolExcutor 2 3 def task(arg): 4 print(arg) 5 6 pool = ThreadPoolExcutor(5) 7 for i in range(10): 8 pool.submit(task,i)
4.協程
1 import greenlet 2 3 def f1(): 4 print(111) 5 g2.switch() 6 print(222) 7 g2.switch() 8 9 def f2(): 10 print(333) 11 g1.switch() 12 print(444) 13 g1.switch() 14 15 g1 = greenlet.greenlet(f1) 16 g2 = greenlet.greenlet(f2) 17 g1.switch()
協程+IO
1 from gevent import monkey 2 monkey.patch_all() 3 import requests 4 import gevent 5 6 def get_page1(url): 7 ret = requests.get(url) 8 print(ret.content) 9 10 def get_page2(url): 11 ret = requests.get(url) 12 print(ret.content) 13 14 def get_page3(url): 15 ret = requests.get(url) 16 print(ret.content) 17 18 gevent.joinall( 19 [ 20 gevent.spwan(get_page1,'https://www.python.org/'), 21 gevent.spwan(get_page1,'https://www.yahoo.com/'), 22 gevent.spwan(get_page1,'https://github.com/'), 23 24 25 ] 26 27 28 )
threading.local的作用:為每個線程開闢一個空間進行數據存儲,自己通過字典創建一個類似於threading.loacl
requests模塊模擬瀏覽器發送請求:
本質:
requests.get(url)
創建socket客戶端
連接,阻塞
發送請求
接收請求,阻塞
斷開連接
同步非同步:
同步過程中進程觸發IO操作並等待或者輪詢的去查看IO操作是否 完成
非同步過程中進程觸發IO操作後直接返回做其他事情
阻塞非阻塞:
應用請求IO操作時,需要等待就是阻塞,請求立即返回就是非阻塞.
阻塞 -> 非阻塞:
client.setblocking(False)
會報錯,需要try
try:
pass
except BlockingIOError as e:
pass
什麼是非同步非阻塞?
非阻塞:不等待,比如創建socket對某個地址進行connect,獲取接收數據recv預設都會等待(連接成功或接收到數據),才執行後續操作.如果設置setblocking(False),以上兩個過程就不會再等待,但是會報BlockingIOError錯誤,只要捕獲即可
非同步:通知,執行完成之後自動執行回調函數或自動執行某些操作.
什麼是同步阻塞?
阻塞:等待
同步:按照順序逐步執行.
IO多路復用:
IO多路復用分為時間上的復用和空間上的復用
空間上的復用是將記憶體分為幾部分,每一部分放一個程式,這樣同一時間記憶體中就有多道程式.
時間上的復用是指多個程式在一個CPU上運行,不同的程式輪流使用CPU.
當某個程式運行時間過長或者遇到IO操作,操作系統會把CPU分配給下一個程式,保證CPU處於高使用率,實現偽併發.
IO多路復用作用:檢測socket是否已經發生變化(是否已經連接成功/是否已經獲取到數據)(可讀/可寫)
操作系統檢測側socket是否發生變化有三種模式:
select:最多1024個socket,迴圈去檢測
pool:不限制監聽socket個數,迴圈去檢測(水平觸發)
epool:不限制監聽個數,回調方式(邊緣觸發)