美文网首页
事件驱动,IO多路复用

事件驱动,IO多路复用

作者: 两分与桥 | 来源:发表于2018-04-30 20:42 被阅读27次

事件驱动

  1. 有一个事件(消息)队列;
  2. 鼠标按下时,往这个队列中增加一个点击事件(消息);
  3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
  4. 事件(消息)一般都各自保存各自的处理函数指针,指向各自的处理函数;

IO多路

当进程进入堵塞状态时,是不占用CPU资源的

blocking IO,一般调用 socket 默认都是堵塞 IO,也就是当 socket 对象 recv 时,如果 recv 不到数据就会一直在堵塞,等待数据到来才进行下一步。
例子:打电话,直等到特定的人来接听才走下一步。

non-blocking IO,设定 sk.setblocking(False),可以设定为非堵塞IO模式,当 recv 不到数据时,立即返回一个错误,错误用 except 去捕捉,这段时间可以让 CPU 执行别的程序,一段时间后再回去 recv ,不断重复,非堵塞 IO 会发起比较多的系统调用,响应延迟增大了,不能立即返回去处理。
例子:打电话,找不到人就隔一段时间再打,一直打到特定的人来听电话。

IO multiplexing , IO 多路复用,用select ,epoll,好处是能同时处理多个连接,但不实用与单个连接。
例子:想不到例子了······

Asynchronous IO ,异步IO, 全程无堵塞的执行程序,等待系统内核通知程序已经完成,直接来取数据就行了。
例子:还是打电话,通知那边的人,叫他那个人到了就通知我,我再来打电话。

多路复用,还分为水平触发和边缘触发。
select 属于水平触发,

我在使用 selectors 模块是时一直报错
报错:[WinError 10035] 无法立即完成一个非阻止性套接字操作。
下面是我的代码

# server 端
import selectors
import socket
import json
import time

class Mytest:
    def __init__(self):
        self.keep = 1
        self.creat_socket()
        self.work()

    def work(self):
        print('wait for connect')
        while True:
            events = self.sel.select()
            for key, mask in events:
                callback = key.data
                callback(key.fileobj, mask)

    def creat_socket(self):
        self.sel = selectors.DefaultSelector()
        self.sock = socket.socket()
        self.sock.bind(('localhost', 8889))
        self.sock.listen(100)
        # self.sock.setblocking(False)
        self.sel.register(self.sock,selectors.EVENT_READ,self.accept)

    def accept(self, sock, mask):
        self.conn, self.addr = sock.accept()  # Should be ready
        print('accepted', self.conn, 'from', self.addr)
        self.conn.setblocking(False)
        self.sel.register(self.conn, selectors.EVENT_READ, self.read)

    def read(self, conn, mask):
        # try:
            data = conn.recv(1024)
            if self.keep == 2:
                func = getattr(self, 'put')
                func(conn,data)
            else:
                print('echoing', repr(data), 'to', conn)
                data = data.decode('utf-8').split()
                if len(data) == 2 :
                    if hasattr(self, data[0]):
                        func = getattr(self, data[0])
                        func(conn,data)
                else:
                    conn.send('please input again'.encode('utf-8'))
        # except Exception as e:
        #     print(e)
        #     print('closing', conn)
        #     self.sel.unregister(conn)
        #     conn.close()

    def put(self, conn, data):
        # 上传
        if self.keep == 1:
            print('put', data)
            self.data_dic = {
                'action' : 'put',
                'file_name' : data[1]
            }
            data = json.dumps(self.data_dic)
            conn.send(data.encode('utf-8'))

            time.sleep(0.1)
            self.file_size = int(conn.recv(1000).decode('utf-8'))

            print('file_size = ', self.file_size)
            print('file_name = ', self.data_dic['file_name'])

            send_size = 0
            f = open(self.data_dic['file_name'], 'wb')

            time.sleep(3)
            test = self.conn.recv(1024)
            f.write(test)
            self.send_size = send_size + len(test)
            f.close()
            self.keep = 2
            print('put first end')
        else:
            f = open(self.data_dic['file_name'], 'ab')
            f.write(data)
            self.send_size = self.send_size + len(data)
            f.close()
            if self.send_size == self.file_size:
                print('put successful')
                self.keep = 1

    def get(self, conn, data):
        # 下载
        print('get', data)
        conn.send('get has none'.encode('utf-8'))

test = Mytest()

# client 端
import socket
import os
import json
import time
import sys

path = os.path.dirname(os.path.abspath(__file__))

class Myclient:
    def __init__(self):
        self.creat_connect()
        self.work()

    def creat_connect(self):
        self.sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.sk.connect(('127.0.0.1',8889))

    def work(self):
        print('connecting to server')
        while True:
            inputs = input('>>>')
            self.sk.send(inputs.encode('utf-8'))
            data = self.sk.recv(1024).decode('utf-8')
            if hasattr(self, inputs.split()[0]):
                func = getattr(self, inputs.split()[0])
                func(data)
            else:
                print(data)

    def put(self, data):
        # 上传
        data = json.loads(data)
        print('put', data)
        paths = os.path.join(path, data['file_name'])
        if os.path.exists(paths):
            file_size = os.stat(paths).st_size
            print('exist , file_size = ', file_size)
            self.sk.send(str(file_size).encode('utf-8'))

            time.sleep(2)
            send_size = 0
            f = open(data['file_name'], 'rb')

            while send_size < file_size:
                test = f.read(1024)
                self.sk.send(test)
                send_size = send_size + len(test)
            f.close()
            print('put end')
        else:
            print('file %s not exist' %data['file_name'])

    def get(self, data):
        # 下载
        print('get', data)

client = Myclient()

因为之前设定的是非堵塞IO, 出现这个问题后我就把 self.sock.setblocking(False) 注释了,但是还是出现这个问题,之后我发现报错的代码是 当 conn 去 recv 时没有数据,就立即报错,但是我在这句之前加了延时,就不会报这个错误了。

还要注意避免两次 socket 的 send 数据粘包情况,这次写的不好,有些问题没有解决,例如不能多个人同时上传文件,应该是有些参数设定得不好。

最近这几天挺多事的,没有静下来学,拖慢进度了。。。真是抱歉

Python这个语言基本就学到这里了,剩下的得靠自己

可以看袁老师的:https://www.cnblogs.com/yuanchenqi/articles/5722574.html

相关文章

  • 事件驱动,IO多路复用

    事件驱动 有一个事件(消息)队列; 鼠标按下时,往这个队列中增加一个点击事件(消息); 有个循环,不断从队列取出事...

  • libevent简介

    -----事件驱动: -----轻量级,专注于网络:只能做网络先关的事 -----支持io多路复用:epool,p...

  • 五种 IO 模型

    五种 IO 模型 参考链接 一共有五种 IO 模型 阻塞 IO 非阻塞 IO 多路复用 IO 信号驱动 IO 异步...

  • io多路复用

    首先需要明确的是,linux有五类io模型1.阻塞2.非阻塞3.io多路复用4.事件驱动5.异步(ps:这里需要的...

  • IO复用

    在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现...

  • epoll用于高并发网络编程,优于select

    在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现...

  • 程序员技能梳理之select、poll和epoll的区别

    在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现...

  • Android 深入底层:Linux事件管理机制 epoll

    在linux 没有实现epoll事件驱动机制之前,我们一般选择用select或者poll等IO多路复用的方法来实现...

  • IO模型

    阻塞IO 非阻塞IO 多路复用IO 信号驱动IO 异步IO 吃午饭之阻塞IO 下单之后,排队等在取餐口等待厨师做好...

  • I/O模型/同步异步阻塞非阻塞

    I/O模型 阻塞式IO 非阻塞式IO I/O多路复用(select,poll,epoll) 信号驱动式IO 异步I...

网友评论

      本文标题:事件驱动,IO多路复用

      本文链接:https://www.haomeiwen.com/subject/ncjtrftx.html