Windows上的python select.select()

2024-09-28 22:24:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用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实现有关,每个人都引用这个:

Note File objects on Windows are not acceptable, but sockets are. On Windows, the underlying select() function is provided by the WinSock library, and does not handle file descriptors that don’t originate from WinSock.

所以我有两个问题:

  1. [0, sockfd]0是什么意思?这是一种常用的技巧吗?
  2. 如果select只在Windows上与socket一起工作,如何使代码窗口兼容?

谢谢你。


Tags: 代码indataifiswindows错误sys
2条回答

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

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()

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

  1. 用于stdin的额外线程。这应该工作得很好,是做这项工作最简单的方法。如果您只需要等待I/O事件,那么Python线程支持就可以了。
  2. 类似于gevent中的greenlet机制,用于修补线程支持的标准库的大多数I/O函数,以防止它们阻塞greenlet。也有类似twisted(请参阅注释)的库提供非阻塞文件I/O。这种方式是最一致的,但它应该要求使用与框架匹配的样式来编写整个应用程序(twistedgevent,差异不显著)。但是,我怀疑twisted包装器不能从Windows上的stdin异步输入(非常肯定它们可以在*nix上执行,因为它们可能使用相同的select)。
  3. 还有别的把戏。然而,大多数可能的伎俩都相当丑陋。

相关问题 更多 >