python之路(16)IO模型、select模块、selectors模块

 目录

  • 阻塞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)
两端交流server端
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")

猜你喜欢

转载自www.cnblogs.com/shuzhixia/p/10835190.html