Python select -> select

Python select -> select

一、select介绍-来自百度百科

select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读或可写。主要用于Socket通信当中。

总结:select主要用于socket通信当中,能监视我们需要的文件描述变化

二、非阻塞时I/O编程-I/O多路复用
这篇文章讲的很详细,就不复述了。

Linux IO模式及 select、poll、epoll详解

三、python中的select

    # In python
    select.select(rlist, wlist, xlist[, timeout]) 

    # In C/C++
    int select(int maxfdpl, fd_set * readset, fd_set *writeset, fd_set *exceptset, const struct timeval * tiomeout)

python的select相对与C省去了文件描述符的参数

select能够监听可读的套接字列表,可写的套接字列表和异常的套接字列表。监听的套接字发生变化时,比如客户端连接,收到客户端消息等都会触发select。timeout指定了监听的超时时间,默认为None,会一直阻塞到套接字事件发生。指定了具体的数字后,在指定的时间内没有套接字事件发生,select会直接返回。select会返回准备好的三个对象列表,是三个输入参数的子集。

下面是测试代码,服务端监听,收到客户端的消息后,发送同样的消息给客户端
服务端代码:

from __future__ import unicode_literals
import socket
import select
import Queue
import logging

logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-4s) %(message)s %(asctime)s')

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)

server_address = ('localhost', 8090)
server.bind(server_address)

server.listen(5)

inputs = [server]

outputs = []

message_queues = {}

while inputs:
    logging.debug('waiting for the next event.')

    rlist, wlist, xlist = select.select(inputs, outputs, inputs)

    for r in rlist:
        if r is server:
            connection, client_address = server.accept()
            logging.debug('connection from: {0}'.format(client_address))

            # 客户端加入监听列表, 服务端收到客户端发送消息时,触发select
            inputs.append(connection)

            # 为连接的客户端单独创建一个消息队列,用来保存客户端发送的消息
            message_queues[connection] = Queue.Queue()

        else:
            # 服务端收到客户端发送消息时,触发select
            data = r.recv(1024)
            if data != '':
                logging.debug('received "{0}" from {1}'.format(data, r.getpeername()))
                message_queues[r].put(data)

                # 将需要进行回复操作的socket放入output,select监听发送
                if r not in outputs:
                    outputs.append(r)

            # 客户端断开
            else:
                logging.debug('closing "{0}"'.format(r.getpeername()))
                if r in outputs:
                    outputs.remove(r)

                if r in inputs:
                    inputs.remove(r)

                if r in message_queues:
                    del message_queues[r]

    for w in wlist:
        try:
            message_queue = message_queues.get(w)
            send_data = ''
            if message_queue is not None:
                send_data = message_queue.get_nowait()
            else:
                logging.debug('closing "{0}"'.format(w.getpeername()))

        except Queue.Empty:
            # 没有收到客户端消息,从发送列表中除去
            outputs.remove(w)

        else:
            logging.debug('send {0} to {1}'.format(send_data, w.getpeername()))
            w.send(send_data)

    for x in xlist:
        logging.debug('exception on {0}'.format(x.getpeername()))
        if x in inputs:
            inputs.remove(x)

        if x in outputs:
            outputs.remove(x)

        if x in message_queues:
            del message_queues[x]

        x.close()

客户端代码:

import socket
import time

sock = socket.socket()

dest = ('localhost', 8090)
sock.connect(dest)

if __name__ == "__main__":
    count = 0
    while count < 3:
        sock.send('hello')
        data = sock.recv(1024)
        if data:
            print(data)
        time.sleep(1)
        count += 1
    sock.close()

以下是运行结果:

(MainThread) waiting for the next event. 2018-09-09 21:19:10,355
(MainThread) connection from: ('127.0.0.1', 12669) 2018-09-09 21:19:12,173
(MainThread) waiting for the next event. 2018-09-09 21:19:12,173
(MainThread) received "hello" from ('127.0.0.1', 12669) 2018-09-09 21:19:12,174
(MainThread) waiting for the next event. 2018-09-09 21:19:12,174
(MainThread) send hello to ('127.0.0.1', 12669) 2018-09-09 21:19:12,174
(MainThread) waiting for the next event. 2018-09-09 21:19:12,174
(MainThread) waiting for the next event. 2018-09-09 21:19:12,174
(MainThread) received "hello" from ('127.0.0.1', 12669) 2018-09-09 21:19:13,174

从运行结果可以看到,客户连与服端的连接、断开和互相传递消息都会触发select。

服务端发送hello给客户触发了两次的原因,我还没找到,后面继续研究吧

参考网址

python select.select模块通信全过程详解
Linux IO模式及 select、poll、epoll详解

猜你喜欢

转载自blog.csdn.net/soga238/article/details/82563142