目录
阻塞IO
非阻塞IO
阻塞IO
当有数据传入传出的时候,接收方必须一致等待数据的接收才可以进行下一步操作,接收方(操作系统)必须等待数据,这个时候是一个阻塞的状态。在socket模块默认的情况下实现sever端就是一个阻塞IO例子
非阻塞IO
与阻塞IO相对的,在接收方等待数据的时候,如果对方没有发送数据,接收方可以进行后面的操作,等待对方将数据发送过来再进行执行之前的操作。具体实现在等待数据的时候,先执行后面的程序,按照一定的时间,反复的去查看,对方是否已经发送了数据。
在socket模块也能实现实现sever端和client端非阻塞IO例子
server端
import time
import socket
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sk.bind(('127.0.0.1',6667))
sk.listen(5)
sk.setblocking(False) #开启非阻塞的状态
print ('waiting client connection .......')
while True:
try:
connection,address = sk.accept() # 进程主动轮询
print("+++",address)
client_messge = connection.recv(1024)
print(str(client_messge,'utf8'))
connection.close()
except Exception as e: #如果对方没有发送数据过来就执行下面的操作
print (e)
time.sleep(4) #相当于每隔4秒进行查看一次数据是否有发送过来
############################
waiting client connection .......
[WinError 10035] 无法立即完成一个非阻止性套接字操作。
[WinError 10035] 无法立即完成一个非阻止性套接字操作。
[WinError 10035] 无法立即完成一个非阻止性套接字操作。
[WinError 10035] 无法立即完成一个非阻止性套接字操作。
select模块
select是IO多路复用的一种实现方式
通过select模块来实现非阻塞IO,通过非多线程的方式实现多用户同时访问服务器
select模块通过水平触发(只要有连接存在就触发)来检测server端是否有客户端连接server端
import socket,select
sk=socket.socket()
sk.bind(("127.0.0.1",9904))
sk.listen(5)
inp=[sk,] #将server端的socket对象加入到列表中
while True:
#(input,output,errorput,time)
r, w, e = select.select(inp, [], [], 5) # select作为监听器(水平触发),来检测是有客户端来访问conn
# 每隔5秒钟执行一次查看,如果对方没有连接,那r为空值
for i in r:#[sk,]
# conn,add=i.accept() #这里没有进行客户端连接的操作,当循环退出后,再次监听,而r依然是存在sk的列表
# print(conn)
print("Hello")
print('>>>>>>')
#当一个客户端连接
################################
>>>>>>
Hello
>>>>>>
Hello
>>>>>>
Hello
>>>>>>
Hello
.....
server端实现多用户连接
import socket,select
sk=socket.socket()
sk.bind(("127.0.0.1",9904))
sk.listen(5)
inp=[sk,]
while True:
r,w,e=select.select(inp,[],[],5) #[sk,conn]
for i in r:#[sk,]
conn,add=i.accept()
print(conn)
print("hello")
inp.append(conn) #在监听列表中添加连接
print('>>>>>>')
importsocketimportselect
sk=socket.socket()
sk.bind(("127.0.0.1",8801))
sk.listen(5)
inputs=[sk,]whileTrue:
r,w,e=select.select(inputs,[],[],5)for obj in r:#[sk,]
if obj==sk:
conn,add=obj.accept()print(conn)
inputs.append(conn)else:
data_byte=obj.recv(1024)print(str(data_byte,'utf8'))
inp=input('回答%s号客户>>>'%inputs.index(obj))
obj.sendall(bytes(inp,'utf8'))print('>>',r)
两端交流server端
importsocket
sk=socket.socket()
sk.connect(('127.0.0.1', 8801))whileTrue:
inp= input(">>>>")
sk.sendall(bytes(inp,"utf8"))
data= sk.recv(1024)print(str(data, 'utf8'))
两端交流客户端
selectors模块
server端
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock, mask):
conn, addr = sock.accept() # Should be ready
print('accepted', conn, 'from', addr)
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read) #绑定连接,如果coon连接有活动,就直接执行read方法
def read(conn, mask):
try:
data = conn.recv(1000) # Should be ready
if not data:
raise Exception
print('echoing', repr(data), 'to', conn)
conn.send(data) # Hope it won't block
except Exception as e:
print('closing', conn)
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost', 8090))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept) #绑定连接,如果sock连接有活动,就直接执行accept方法
print("server.....")
while True:
events = sel.select()#[sock,,conn2]
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
服务端
import socket
sk=socket.socket()
sk.connect(("127.0.0.1",8090))
while 1:
inp=input(">>>")
sk.send(inp.encode("utf8"))
data=sk.recv(1024)
print(data.decode("utf8")