美文网首页编程杂谈
Socket Block Non-Block Python描述

Socket Block Non-Block Python描述

作者: eye_water_ | 来源:发表于2018-11-24 17:38 被阅读5次

    本文的图片均非原创,均来源自于:
    java Selector is asynchronous or non-blocking architecture
    阻塞模式下[1]

    image

    一段话描述阻塞与非阻塞的区别:[2]
    假设我们在设计一个浏览器,用它来进行网页服务器的访问,如果设计为阻塞模式,那么当我们浏览一个网页长时间未响应时,按下了关闭按钮,会发生什么呢?关闭不掉!因为我们使用的阻塞模式来进行网页服务器的访问,那么在网页服务器返回数据之前或者未达到设定的超时时间之前,不能做任何事情。
    但是如果我们使用非阻塞模式来设计浏览器,那么我们不必等待网页服务器的响应就可以做其它事情。

    非阻塞的连接看起来就像下面这样:[1]

    image
    当我们建立了一个连接,可以不用等网页服务器的数据返回就可以接着做其它事情,当网页服务器准备好数据了,便会通知程序:数据准备好了,快来调用我吧。

    下面我们来编写一个客户端服务器模型来理解以下阻塞以及非阻塞

    server.py

    import socket
    import time
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 5000))
    sock.listen(1)
    while True:
        sc, sockname = sock.accept()
        print('I have accepted a connection from', sockname)
        print('Socket name: ', sc.getsockname())
        print('Socket peer: ', sc.getpeername())
        message = sc.recv(64)
        print('Recevied info is ', repr(message))
        time.sleep(3)//返回数据之前,先暂停3s
        sc.sendall(b'Response from server')
        sc.close()
    

    block-client.py

    import socket
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('localhost', 5000))
    sock.send(b'Resquest from client')
    response = sock.recv(64)
    sock.close()
    print(response)
    print('Test for blocking')//阻塞模式下,这条信息会在3s后才能输出
    

    运行结果如下:


    阻塞模式

    unblock-client.py [3]

    from selectors import *
    import socket
    
    def connected(key, mask):
        selector.unregister(key.fd)
        sock.send(b'Resquest from client')
        selector.register(key.fd, EVENT_READ, read_response) #注册为一个读的event
        print('Test for non blocking')
        
    def read_response(key, mask):
        global stopped
        response = sock.recv(64)
        print(response)
        selector.unregister(key.fd)
        stopped = True
        
    selector = DefaultSelector()
    stopped = False
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #注册为一个写的event
    sock.setblocking(False)
    try:
        sock.connect(('localhost', 5000))
    except:
        pass
    selector.register(sock.fileno(), EVENT_WRITE, connected)
    while not stopped:
        events = selector.select()#选取已经准备好的event
        for event_key, event_mask in events:
            callback = event_key.data
            callback(event_key, event_mask) #回调函数
    

    运行结果

    非阻塞模式
    在非阻塞模式中,把读和写注册为event,在它们未准备好之前,我们先可以执行其它的程序,在它们准备好之后,利用回调函数来进行程序的执行。
    对于上面的程序我们可以这样来解释,当我们要在socket中写入数据时,把它注册为一个event,当写入的操作准备好时再写入,在写入操作未准备好时,我们可以执行其它的程序
    我们可以把写入的操作定义为一个回调函数,当系统提醒我们说:文件准备好了,可以开始写了。我们就会调用回调函数connected

    何为event?[4]
    在特定的时间执行特定的程序或者说依据文件描述符来执行特定的程序

    何为回调函数?[5]
    1.可以被其它函数调用的函数
    2.当调用它的函数完成后,会执行它

    在写入操作完成后,我们就需要进行读取操作了,这时精彩的地方来了,程序会先输出Test for non blocking

    为什么呢?
    因为读取操作还没准备好,注意我们在server.py中写入了time.sleep(3),因此三秒之内读取操作是不会准备好的,这时就会执行其它程序,因此会先输出Test for non blocking

    PS:
    如果有什么错误或者疑问,可以在评论区指出


    1. 图片来源于 java Selector is asynchronous or non-blocking architecture

    2. 这段话的描述其实出自Blocking vs. non-blocking sockets这里,里面的关于浏览器的例子举得实在是很棒

    3. 关于非阻塞模式,其实是在阅读aosabook/500lines中得到的知识,不得不说这个项目实在是太强了,虽然代码很少,但理解起来很难

    4. 关于event的描述其实是在搜索event API时找到的,描述的很好event(3) - Linux man page

    5. 回调函数的描述摘自于https://stackoverflow.com/questions/824234/what-is-a-callback-function

    相关文章

      网友评论

        本文标题:Socket Block Non-Block Python描述

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