Windows上的python select.select()

时间:2014-03-07 13:45:50

标签: python windows sockets select

我正在使用here中的代码测试UDP打孔。它适用于Linux,但在Windows上报告错误。以下是发生错误的代码段:

while True:
    rfds, _, _ = select([0, sockfd], [], [])  # sockfd is a socket
    if 0 in rfds:
        data = sys.stdin.readline()
        if not data:
            break
        sockfd.sendto(data, target)
    elif sockfd in rfds:
        data, addr = sockfd.recvfrom(1024)
        sys.stdout.write(data)

错误消息:

Traceback (most recent call last):
  File "udp_punch_client.py", line 64, in <module>
    main()
  File "udp_punch_client.py", line 50, in main
    rfds, _, _ = select([0, sockfd], [], [])
select.error: (10038, '')

我知道这个错误与Windows上的select实现有一些关系,每个人都引用这个:

  

注意 Windows上的文件对象是不可接受的,但套接字是。上   Windows,底层的select()函数由WinSock提供   库,并不处理不起源的文件描述符   来自WinSock。

所以我有两个问题:

  1. 0中的[0, sockfd]是什么意思?这是一种经常使用的技术吗?
  2. 如果select仅适用于Windows上的socket,如何使代码与Windows兼容?
  3. 谢谢。

2 个答案:

答案 0 :(得分:4)

不幸的是,select无法帮助您在一个线程中处理stdin和网络事件,因为select无法在Windows上使用流。您需要的是一种无阻塞地阅读stdin的方法。你可以使用:

  1. stdin的额外帖子。这应该工作正常,是最简单的工作方式。如果您需要的只是等待I / O事件,那么Python线程支持就可以了。
  2. 类似于greenletgevent机制,用于修补线程支持以及标准库的大多数I / O函数,以防止它们阻塞greenlet。还有像twisted这样的库(请参阅注释)提供非阻塞文件I / O.这种方式是最一致的,但它应该要求使用与您的框架匹配的样式(twistedgevent来编写整个应用程序,差异并不重要)。但是,我怀疑twisted包装器无法在Windows上stdin进行异步输入(非常确定它们可以在* nix上执行此操作,因为它们可能使用相同的select)。
  3. 其他一些技巧。但是,大多数可能的技巧都相当难看。

答案 1 :(得分:3)

正如答案所示,我创建另一个线程来处理输入流并且它可以工作。 这是修改后的代码:

sock_send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

def send_msg(sock):
    while True:
        data = sys.stdin.readline()
        sock.sendto(data, target)

def recv_msg(sock):
    while True:
        data, addr = sock.recvfrom(1024)
        sys.stdout.write(data)

Thread(target=send_msg, args=(sock_send,)).start()  
Thread(target=recv_msg, args=(sockfd,)).start()