首页 > 解决方案 > 选择 call only 在 tcp 输入上工作两次。如何正确使用 select 与 tcp 和 udp 服务器?

问题描述

我正在创建一个服务器,它使用 select() 在 Python 中进行非阻塞 i/o。

我有一个选择输入为 TCP 连接和 UDP 连接的服务器。在 TCP 连接中,可能会调用其他 UDP 服务器。问题是我的服务器在运行服务器时只检查 TCP 输入两次,并且与其他 UDP 服务器(不是服务器自己的 UDP 服务器)进行了一些数据传输。如果不需要 UDP 传输,那么它的工作次数与 Web 浏览器调用的次数一样多。

除了我只能发送 TCP 请求两次的奇怪情况之外,我的服务器似乎工作正常。

我还怀疑我能够发送两次,因为浏览器的一些 favicon 请求和实际请求将 's' 两次作为输入并且在它之后不起作用。我还认为我如何将 select 用于服务器自己的 UDP 连接可能存在问题。

这是我第一次编写服务器程序,所以一般来说我如何处理选择函数和套接字可能存在一些直截了当的问题。

inputs = [ server, udp ]

# Sockets to which we expect to write
outputs = [ ]

# Outgoing message queues (socket:Queue)
message_queues = {}

while inputs:
    # Wait for at least one of the sockets to be ready for processing
    print('\nwaiting for the next event')
    readable, writable, exceptional = select.select(inputs, outputs, inputs)

这有点像我的可读输入循环的样子:

        if s is server:
            connection, client_address = s.accept()
            connection.setblocking(0)
            inputs.append(connection)
            message_queues[connection] = queue.Queue()
        elif s != udp:
            print(readable)
            try:
                data = s.recv(4096)
                if data:
                    # do something
                    message_queues[s].put(data)
                    if s not in outputs:
                        outputs.append(s)
                else:
                    # Interpret empty result as closed connection
                    print('closing', client_address, 'after reading no data')
                    if s in outputs:
                        outputs.remove(s)
                    inputs.remove(s)
                    s.close()
                    del message_queues[s]
            except Exception:
                if s in outputs:
                    outputs.remove(s)
                inputs.remove(s)
                s.close()
        if s is udp:
            print(s)
            udpdata,addr = s.recvfrom(UDP_PORT_NO)

这有点像我的可写循环的样子:

for s in writable:
        try:
            next_msg = message_queues[s].get_nowait()

            if (something):
                udp_others = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                try:
                    # Send data
                    sent = udp_others.sendto(packet.encode(), ('localhost', destination_port))
                    # Receive response
                    clientdata, server = udp_test.recvfrom(4096)
                    # do something with data
                finally:
                    print ('closing socket')
                    udp_others.close()

            next_msg = "Hello"
        except queue.Empty:
            # No messages waiting so stop checking for writability.
            print('output queue for', s.getpeername(), 'is empty')
            outputs.remove(s)
        else:
            print(response)

    # Handle "exceptional conditions"
    for s in exceptional:
        print >>sys.stderr, 'handling exceptional condition for', 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]

标签: pythonsocketsselecttcpudp

解决方案


推荐阅读