我正在使用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的文件描述符 .
所以我有两个问题:
-
[0, sockfd]
中的0
是什么意思?这是一种经常使用的技术吗? -
如果
select
仅适用于Windows上的socket
,如何使代码与Windows兼容?
谢谢 .
2 回答
正如答案所示,我创建另一个线程来处理输入流,它的工作原理 . 这是修改后的代码:
遗憾的是,
select
无法帮助您在一个线程中处理stdin
和网络事件,因为select
无法在Windows上使用流 . 你需要的是一种无阻塞地读取stdin
的方法 . 你可以使用:stdin
的额外线程 . 这应该工作正常,是最简单的工作方式 . 如果您需要的只是等待I / O事件,Python线程支持是完全可以的 .类似于gevent的greenlet机制,它修补了线程支持和标准库的大多数I / O函数,以防止它们阻塞greenlet . 还有像
twisted
这样的库(参见注释)提供了非阻塞文件I / O.这种方式是最一致的,但它应该要求使用与您的框架匹配的样式来编写整个应用程序(twisted
或gevent
,差异并不重要) . 但是,我怀疑twisted
包装器无法在Windows上从stdin
进行异步输入(非常确定它们可以在* nix上执行此操作,因为它们可能使用相同的select
) .其他一些技巧 . 然而,大多数可能的技巧都相当丑陋 .