1.IO是什么?
?定義
在內(nèi)存中存在數(shù)據(jù)交換的操作
和終端交互:input, output
和磁盤交互:read, write
和網(wǎng)絡(luò)交互:recv, send
①IO密集型:在程序當(dāng)中存在大量的IO,而CPU的運(yùn)算較少,消耗CPU資源小,耗時(shí)長(zhǎng),效率不高
②計(jì)算密集型:在運(yùn)算中存在大量計(jì)算,IO行為較少,CPU消耗大,執(zhí)行速度快
? 阻塞IO
定義:在執(zhí)行IO操作時(shí)由于不滿足某些條件形成的阻塞形態(tài)
效率:阻塞IO是一種效率很低的IO,邏輯簡(jiǎn)單。
? 非阻塞IO
定義:通過修改IO的屬性行為,使原本阻塞的IO變?yōu)榉亲枞臓顟B(tài)
修改方法:
sockf.setblocking(bool)
功能:設(shè)置套接字為非阻塞IO
參數(shù):True為阻塞,F(xiàn)alse為非阻塞
Sockf.settimeout(sec)
功能:超時(shí)檢測(cè),阻塞等待的時(shí)間,超時(shí)后不再阻塞
參數(shù):超時(shí)時(shí)間,以秒為單位
2.IO多路復(fù)用
定義
同時(shí)監(jiān)控多個(gè)IO事件,當(dāng)哪個(gè)IO事件準(zhǔn)備就緒就執(zhí)行哪個(gè)IO,以此形成可以同時(shí)處理多個(gè)IO的行為。避免一個(gè)IO阻塞造成其他IO無法執(zhí)行,提高IO執(zhí)行效率。
具體方案:①select: windows/linux/unix
②poll: linux/unix
③epoll: linux
select具體用法
①導(dǎo)入: from select import select
②監(jiān)控IO:
rs,ws,xs = select(rlist,wlist,xlist)
功能:監(jiān)控多個(gè)IO事件,阻塞等待IO發(fā)生
參數(shù):rlist 列表,關(guān)注的等待發(fā)生的IO事件
wlist 列表,要主動(dòng)處理的IO事件
xlist 列表,發(fā)生異常時(shí)要處理的IO事件
返回值:
rs: 列表,rlist中準(zhǔn)別就緒的IO
ws: 列表,wlist中準(zhǔn)別就緒的IO
xs: 列表, xlist中準(zhǔn)別就緒的IO
③注意:
- wlist 中如果有IO事件,select 會(huì)立即返回為ws
*處理事件過程找那個(gè)不要出現(xiàn)死循環(huán)等長(zhǎng)期占有服務(wù)端的情況
*IO多路復(fù)用消耗資源較少,效率較高 - 套接字獲取地址的方法:
sockfd.getpeername() 返回一個(gè)元組: (ip,port)
3.實(shí)現(xiàn)多路復(fù)用局域網(wǎng)文件傳輸
server.py
from select import *
from socket import *#導(dǎo)入模塊
from FileOperation import *
ip_address = "0.0.0.0"#設(shè)置IPV4地址
port = 8097#設(shè)置端口
num = 3#設(shè)置監(jiān)聽數(shù)量
addrs = []
server = socket(
family=AF_INET,
type = SOCK_STREAM,
proto = 0
)
server.bind((ip_address,port))
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,True)
#SO_REUSEADDR指的是一個(gè)網(wǎng)絡(luò)地址在短時(shí)間重復(fù)利用
server.listen(num)
print("server is listening to the port:%d"%port)
print("server can be connected for %d clients at the same time "%num)
print("------------------------------------")
rlist = [server]#存放關(guān)注的,等待發(fā)生的IO事件
wlist = []#存放主動(dòng)處理的IO事件
xlist = []#存放發(fā)生異常的事件
while True:
rs,ws,xs = select(rlist,wlist,xlist)
for i in rs:#遍歷準(zhǔn)備就緒的IO事件,如果準(zhǔn)備就緒的IO事件i,如果i等于服務(wù)器server時(shí),有客戶端連接上來了。
if i is server:
coon,addr = i.accept()#連接
rlist.append(coon)
print(addr,"is connected......")
addrs.append(addr)
else:#如果i等于連接套接字類型,那就去接收
data = i.recv(102400)#阻塞等待發(fā)送消息
msg = data
add_file("./vmware-1.exe",msg)
if msg == "quit":#客戶端要求斷開連接
rlist.remove(i)
i.close()
continue
else:
i.send(b"ok")#向客戶端反饋OK信息
server.close()
client.py
from socket import *#導(dǎo)入socket庫
import time
from FileOperation import *
global server_ip
global server_port
server_ip = "192.168.75.1"#這里使用cmd查看主機(jī)ipv4地址
server_port = 8097
client = socket(
family = AF_INET,
type = SOCK_STREAM,
proto = 0)
while True:
try:#服務(wù)端未打開時(shí)的異常
client.setsockopt(SOL_SOCKET,SO_REUSEADDR,True)
client.connect((server_ip,server_port))
except:
print("您是不是遠(yuǎn)離服務(wù)器了,靠近后再試一試!")
server_ip = input("如果ip接口輸入錯(cuò)誤,請(qǐng)?jiān)谶@里重試:")
server_port = input("如果ip端口輸入錯(cuò)誤,請(qǐng)?jiān)谶@里重試:")
print("正在重試中...")
print(server_ip)
print(server_port)
else:
break
while True:
msg,read_bool = open_file("vmware.exe")
client.send(msg)
if msg == "quit":
break
data = client.recv(1024)
msg = data.decode()
print("server:%s"%msg)
client.close()
FileOperation.py
def open_file(dir):
ReadBool = None
msg = None
try:
with open(dir,"rb")as f:
msg = f.read()
except:
pass
else:
ReadBool = True
return msg,ReadBool
def write_file(dir,message):
WriteBool = None
msg = None
try:
with open(dir,"wb+")as f:
f.write(message)
f.close()
except:
pass
else:
WriteBool = True
return msg,WriteBool
def add_file(dir,message):
AddBool = None
msg = None
try:
with open(dir,"ab+")as f:
f.write(message)
f.close()
except:
pass
else:
AddBool = True
return msg,AddBool
注意事項(xiàng)
-
msg,read_bool = open_file("vmware.exe")
是作者電腦中包含的文件,當(dāng)使用TCP傳輸時(shí),要記得將這個(gè)地方換成電腦中的可讀取文件,不然程序會(huì)報(bào)錯(cuò) -
server_ip = "192.168.75.1"
這里要轉(zhuǎn)換為服務(wù)器的ipv4地址 - 要先打開server.py文件,再打開client.py。最好是在命令行運(yùn)行