zoukankan      html  css  js  c++  java
  • Python实现socket的非阻塞式编程

    Python实现socket的非阻塞式编程

    原文
    阻塞模式与非阻塞模式

    阻塞模式 程序碰到了一些耗时操作,无法继续向下走。

    例如在socket编程中,例如在send()即发送信息过程中,可能对方已经断开,可能网络等原因导致信息传递不通畅;在客户端的connect()函数中,可能地址不可达等原因。这些情况在阻塞模式中会造成线程中断等待,导致无法进行下一步操作,等超过一个固定时间还没有完成之后会产生异常。但是这种阻塞通常用于确定的几个连接地址并且必须准确连接上。

    非阻塞模式 当程序碰到耗时操作,分发给别的线程,主线程继续执行。

    例如在socket编程中,在send()或connect()函数中,程序会抛出异常10035,在非阻塞模式下无法完成耗时操作,但是程序会继续走下去,不会阻塞到当前的程序。那么,怎么判断什么时候程序完成这些耗时操作呢?select闪亮登场。
    Python网络编程-IO阻塞与非阻塞及多路复用
    基于select的网络编程
    在python中,select函数是一个队底层操作系统直接访问的接口,它用来监控sockets、files和pipse,等待IO完成。当有可读、可写或者是异常事件产生时,select函数可以监控到。
    r, w, e, = select.select(rlist, wlist, xlist[, timeout]) 传递三个参数,一个为输入而观察的文件对象列表,一个为输出而观察的文件对象列表和一个观察错误异常的文件列表。第四个是一个可选参数,表示超时秒数。这个就是系统级别的阻塞,如果监控到事件会直接传递到这里。

    具体的客户端非阻塞连接如下,使用的是python3.6

    # -*- coding: UTF-8 -*-
    # python使用select进行非阻塞模式编程,客户端程序
    import socket
    import select
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    # 生成socket
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 不经过WAIT_TIME,直接关闭
    sock.setblocking(False)                                     # 设置非阻塞编程
    
    try:
        # sock.connect(("google.com", 80))
        sock.connect(("192.168.1.106", 789))
    except Exception as e:
        print(e)
    
    r_inputs = set()
    r_inputs.add(sock)
    w_inputs = set()
    w_inputs.add(sock)
    e_inputs = set()
    e_inputs.add(sock)
    
    while True:
        try:
            r_list, w_list, e_list = select.select(r_inputs, w_inputs, e_inputs, 1)
            print("r")              # 产生了可读事件,即服务端发送信息
            for event in r_list:
                try:
                    data = event.recv(1024)
                except Exception as e:
                    print(e)
                if data:
                    print(data)
                    print("收到信息")
                else:
                    print("远程断开连接")
                    r_inputs.clear()
            print("w")
            if len(w_list) > 0:     # 产生了可写的事件,即连接完成
                print(w_list)
                w_inputs.clear()    # 当连接完成之后,清除掉完成连接的socket
            print("e")
            if len(e_list) > 0:     # 产生了错误的事件,即连接错误
                print(e_list)
                e_inputs.clear()    # 当连接有错误发生时,清除掉发生错误的socket
        except OSError as e:
            print(e)
    

    python的select注意事项

    除了select,还有什么提高效率的神器
    select,poll,epoll优缺点及比较
    深度理解select、poll和epoll
    通过上述文章可知效率对比 epoll > poll > select
    但是在windows系统上只有select,所以常常用以下判断

    if hasattr(select, 'epoll'):
                self._impl = select.epoll()
                model = 'epoll'
            elif hasattr(select, 'kqueue'):
                self._impl = KqueueLoop()
                model = 'kqueue'
            elif hasattr(select, 'select'):
                self._impl = SelectLoop()
                model = 'select'
    

    切记如果在非阻塞情况下缠上了10035的错误,那是正常反应,我们只需用select进行获取即可。

  • 相关阅读:
    从 OKR 工作法到 OKRs-E,落地OKR不能错过的转变
    OKR : 不要让目标仅仅成为口号
    [MySQL]Software caused connection abort: recv failed 问题分析与解决
    VS2010 vcpkgsrv.exe进程CPU占用高的解决方法
    Lync Server 2013企业版部署系列之九:前端部署后续工作
    Lync Server 2013企业版部署系列之八:安装lync server系统
    Lync Server 2013企业版部署系列之七:使用拓扑生成器规划拓扑
    Lync Server 2013企业版部署系列之六:AD准备
    Lync Server 2013企业版部署系列之五:前端服务器软件准备
    Lync Server 2013企业版部署系列之四:SQL准备
  • 原文地址:https://www.cnblogs.com/sophiascpn/p/15214456.html
Copyright © 2011-2022 走看看