Python之io概念

"""
同步,异步:
强调结果,调用者最终是否得到想要的结构
阻塞非阻塞:
强调时间是否等待

io二个阶段
1.数据准备阶段
2.内核空间复制回用户空间缓冲区阶段

发生io时候
1.内核从输入设备读,写数据
2.进程从内核复制数据

io模型
1.同步io包括阻塞io,非阻塞io,io多路复用
    阻塞io:进程等待(阻塞),直到读写完成
    非阻塞io:
        进程调用read操作,如果io没有准备好,立即返回error,进程不阻塞
        用户可以再次发起系统调用,内核准备好,就阻塞,复制数据到用户空间
    io多路复用:
        就是同时监控多个io,有一个准备好,就不需要等待了开始处理,提高了同时处理io的功能
        select所以的平台都支持,poll是对其的升级,epoll对poll的曾强增加回调机制,select最多监控
        1024个fd,select轮询的方式,效率低下
        epoll,fd没有上限,并且是回调机制,不需要遍历,效率高
2.异步io
进程发起异步io请求,立即返回,内核完成io的二个阶段,内核给进程发一个信号
linix aio的系统调用
"""
'''
abstractmethod register(fileobj,events,data=None)
为selector注册一个文件对象,监视他的io事件
fileobj被监视文件对象,例如socket
events事件,该文件对象必须等待的事件
data可选的与此文件对象相关联的不透明数据,例如关联用来存储每个客户端的会话id
event_read 可读0b01内核准备好输入输出设备,可以开始读了
event_write可写0b10内核准备好了,可以写了
'''  

io多路复用

import selectors
import socket
#在winodws上使用的是select,移植到linux就是epoll
#recv,send就是io操作
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) #产生new_socket的时候调用read函数

def read(conn, mask):
    data = conn.recv(1000)  # Should be ready
    if data:
        print('echoing', repr(data), 'to', conn)
        conn.send(data)  # Hope it won't block
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

sock = socket.socket()   #产生fileobj
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False) #非阻塞,要求
sel.register(sock, selectors.EVENT_READ, accept) ##参数fileobj,events,data=None(回调函数,或者数据)
'''
产生socket,就是有连接请求,传给回调函数执行 sock,selectors.EVENT_READ说明socket和读就绪后执行accept
'''
# key = sel.register(sock, selectors.EVENT_READ, accept) key有四个属性,fileobj,fd,events,data


while True:
    events = sel.select() #阻塞,直到events(读,写)
    for key, mask in events:  #key有四个属性,fileobj,fd,envets,data(accept,read等回调函数)
        callback = key.data    #当socket接入时,key.data = accept
        callback(key.fileobj, mask)  #accept(key.fileobj,mask) ,key.ffileoj就是sock

 

import socket
import threading
import datetime
import selectors

class ChatServer:
    def __init__(self,ip='127.0.0.1',port=9999):
        self.sock = socket.socket
        self.addr = (ip,port)
        self.event = threading.Event()
        self.selector = selectors.DefaultSelector()

    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        self.sock.setblocking(False)
        self.selector.register(self.sock,selectors.EVENT_READ,self.accept)
        threading.Thread(target=self.select,daemon=True).start()

    def select(self):
        while not self.event.is_set():
            events = self.selector.select()
            for key,mask in events:
                callback = key.data
                callback(key.fileobj)

    def accept(self,sock:socket.socket):
        conn,addr = sock.accept()
        conn.setblocking(False)
        self.selector.register(conn,selectors.EVENT_READ,self.receive)

    def receive(self,sock:socket.socket):
        data = sock.recv(1024)
        if data ==b"":
            self.selector.unregister()
            self.sock.close()
            return
        msg = '{}:{}\n{}\n'.format(*sock.getpeername(),data.decode())
        for key in self.selector.get_map().values():
            if key.data==self.receive: #排除self.accept
                key.fileobj.send(msg)
    def stop(self):
        self.event.set()
        fobjs = []
        for fd,key in self.selector.get_map().items():
            fobjs.append(key.fileobj)
        for fobj in fobjs:
            self.selector.unregister(fobj)
            fobj.close()
        self.selector.close()

def main():
    cs  = ChatServer()
    cs.start()
    while True:
        cmd = input(">>>")
        if cmd == 'quit':
            cs.stop()
            break
if __name__ == '__main__':
    main()

 

posted @ 2018-06-20 15:05  亚洲哈登  阅读(553)  评论(0编辑  收藏  举报