02select监听服务端

# can_read, can_write, _ = select.select(inputs, outputs, None, None)## 第一个参数是我们需要监听可读的套接字, 第二个参数是我们需要监听可写的套接字, 第三个参数使我们需要监听异常的套接字, 第四个则是时间限制设置.## 如果监听的套接字满足了可读可写条件, 那么所返回的can,read 或是 can_write就会有值了, 然后我们就可以利用这些返回值进行随后的操作了。相比较unix 的select模型, 其select函数的返回值是一个整型, 用以判断是否执行成功.## 第一个参数就是服务器端的socket, 第二个是我们在运行过程中存储的客户端的socket, 第三个存储错误信息。# 重点是在返回值, 第一个返回的是可读的list, 第二个存储的是可写的list, 第三个存储的是错误信息的# list。import select, socket, queuefrom time import sleep

# 创造一个 TCP/IP连接server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置socket为异步模式。server.setblocking(False)

# 绑定IP地址和端口# 创建一个IP,端口,本地IPserver_address = ('localhost', 8090)print('starting up on %s port %s' % server_address)# 绑定IP和端口server.bind(server_address)

# 设置服务端监听数量server.listen(3)inputs = [server]# 处理要发送的数据outputs = []

# 输出的消息队列message_queues = {}

while inputs:    # 等待至少一个连接开始调用线程    print("waiting for the next event")    # 开始select监听,对input_list中的服务器端的server开始进行监听    # 一旦调用socket的send,recv函数,将会再次调用此模块    # 这里监控三个参数,第一个返回的是可读的list, 第二个存储的是可写的list, 第三个存储的是错误信息的    readable, writable, exceptional = select.select(inputs, outputs, inputs)

    # 处理输入    # 循环判断是否有客户端连接进来,当有客户端连接进来的时候select将进行触发    for s in readable:        # 判断当前触发的是不是服务端对象,当触发的是服务端对象, 说明有新的客户端连接进来了        if s is server:            # 和客户端建立连接            connection, client_address = s.accept()            # 打印客户端的链接            print('connection from', client_address)            # 设置socket为异步模式。            connection.setblocking(0)            # 将客户端对象也加入到监听列表中,当客户端发送消息的时候select也会触发。            inputs.append(connection)

            # 为连接的客户端单独建立一个消息队列,用来保存客户端发送的消息            message_queues[connection] = queue.Queue()        else:            # 有老用户发送消息,处理接收            # 由于客户端连接进来的时候服务端接收客户端的请求,将客户端也加入到了监听列表。            # 客户端发送的消息将触发。            # 判断触发对象是否为客户端            # 接收客户端的信息            data = s.recv(1024)            # 客户端没有断开            if data != '':                # 一个可用的客户端发送了数据                print('received "%s" from %s' % (data, s.getpeername()))                # 将接受到的消息放到对应的客户端的消息队列中                message_queues[s].put(data)                # 将需要进行回复操作的socket放到output列表中,让select监听                # 这里我们如果收到消息将服务端添加进入输出列表。                # 然后select就会监听到,                if s not in outputs:                    outputs.append(s)            else:                # 客户端被监听到有变化,不是有客户端传过来的消息,就是客户端断开了。                # 客户端断开了连接,将客户端的监听从input列表中移除                print('closing', client_address)                if s in outputs:                    outputs.remove(s)                inputs.remove(s)                s.close()

                # 移除对应的socket客户端对象的消息队列                del message_queues[s]

    # 处理输出。    # 如果现在没有客户端的请求,也没有客户端发送消息时,开始对发送的消息列表进行处理。    # 判断是否需要发送消息。    # 存储哪个客户端发送了消息。    for s in writable:        try:            # 如果消息队列中有消息,就从消息队列中获取要发送的消息。            message_queue = message_queues.get(s)            sent_data = ''            if message_queues is not None:                # 如果队列为空的话不等(阻塞)                send_data = message_queue.get_nowait()            else:                # 客户端断开连接了                print('has closed')        # 如果队列为空的话,就代表着发送的消息完了,就需要从队列中删除。        except queue.Empty:            print('%s' % (s.getpeername()))            outputs.remove(s)        else:            # print "sending %s to %s " % (send_data, s.getpeername)            # print "send something"            if message_queue is not None:                s.send(send_data)            else:                print("has closed ")

            # del message_queues[s]            # writable.remove(s)            # print "Client %s disconnected" % (client_address)

            # # Handle "exceptional conditions"        # 处理异常的情况        # 如果有异常情况,那么就从输出队列中删除,然后关闭连接。        for s in exceptional:            print('exception condition on', s.getpeername())            # Stop listening for input on the connection            inputs.remove(s)            if s in outputs:                outputs.remove(s)            s.close()

            # Remove message queue            del message_queues[s]

        sleep(1)
(0)

相关推荐