目录
- 阻塞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('>>>>>>')
import socket import select sk=socket.socket() sk.bind(("127.0.0.1",8801)) sk.listen(5) inputs=[sk,] while True: 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)
import socket sk = socket.socket() sk.connect(('127.0.0.1', 8801)) while True: 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")