1. 程式人生 > >多路復用 阻塞/非阻塞IO模型 網絡IO兩個階段

多路復用 阻塞/非阻塞IO模型 網絡IO兩個階段

叠代 服務端 server mov adp wait 占用 ddr 但是

1.網絡IO的兩個階段 waitdata copydata
send 先經歷:copydata階段
recv 先經歷:waitdata階段 再經歷 copydata階段


2.阻塞的IO模型
之前寫的都是阻塞 無論多線程 多進程 還是進程池 線程池


3.非阻塞IO模型
非阻塞:最直接的體現 所有和讀寫相關的函數 都不會阻塞
意味著 在讀寫的時候 並不能確定目前是否可以讀寫 一旦不能讀寫就派出異常
只能使用try except 看是否可以讀寫
在非阻塞io中 需要不斷循環詢問操作是否需要處理的數據
這樣一來 對應程序而言 效率確實高了
但是操作系統而言 你的程序就像一個病毒 一直強行占用cpu
當你的TCP程序 沒有連接 沒有數據接受 沒有數據發送時 就是在做無用循環 浪費系統資源



4.多路復用 待改:有中間select recv等待結果
核心函數select
幫你檢測所有的連接 找出可以被處理(可以讀寫)的連接
作為處理數據的一方 不再需要重復去向系統詢問 select給你誰,你就用誰來處理


舉例待改

舉例1:叠代期間不能修改被叠代的對象
# li = [1,2,3,4,5,6]
# def mytlist_iter():
# for i in range(len(li)):
# yield li[i]
# for j in mytlist_iter():
# if j == 5:
# li.remove(5)
# d = {"a":1,"b":2}
# for k in d:
# if k == "a":
# d.pop(k)

舉例2:(多路復用)
服務端:
from concurrent.futures import ThreadPoolExecutor
import socket

server = socket.socket()
# 重用端口
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

server.bind(("192.168.11.210",9999))

server.listen(5)

# 設置是否為阻塞 默認阻塞
server.setblocking(False)

def data_handler(conn):
print("一個新連接..")
while True:
data = conn.recv(1024)
conn.send(data.upper())
# 已連接的客戶端
clients = []
# 需要發送的數據
send_datas = []
# 已經發送完的 需要刪除的數據
del_datas = []
# 待關閉的客戶端
closed_cs = []
while True:
try:
conn,addr = server.accept()
# 切到處理數據的任務去執行
# 代碼走到這裏才算是連接成功
# 把連接成功的客戶端存起來
clients.append(conn)
except BlockingIOError:
# print("沒有可以處理的連接 就幹別的活兒")
#要處理的是已經連接成功的客戶端
# 接收數據
for c in clients:
try:
data = c.recv(1024)
if not data:
# 對方關閉了連接
c.close()
# 從客戶端列表中刪除它
closed_cs.append(c)
continue
print("收到%s" % data.decode("utf-8"))
# 現在非阻塞 send直接往緩存賽 如果緩存滿了 肯定有錯誤 需要單獨處理發送
# c.send(data.upper())
send_datas.append((c,data))
except BlockingIOError:
pass
except ConnectionResetError:
# 對方關閉了連接
c.close()
# 從客戶端列表中刪除它
closed_cs.append(c)
# 處理發送數據
for data in send_datas:
try:
data[0].send(data[1].upper())
# 發送成功需要刪除 不能直接刪除
# send_datas.remove(data)
del_datas.append(data)
except BlockingIOError:
continue
except ConnectionResetError:
# 客戶端連接需要刪除
data[0].close()
closed_cs.append(data[0])
# 等待發送的數據需要刪除
del_datas.append(data)
# 刪除無用的數據
for d in del_datas:
#從待發送的列表中刪除
send_datas.remove(d)
del_datas.clear()
for c in closed_cs:
clients.remove(c)
closed_cs.clear()

客戶端:
import socket

c = socket.socket()

c.connect(("127.0.0.1",9999))

while True:
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
data = c.recv(1024)
print(data.decode("utf-8"))

多路復用 阻塞/非阻塞IO模型 網絡IO兩個階段