我正在使用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
中的[0, sockfd]
是什么意思?这是一种经常使用的技术吗? select
仅适用于Windows上的socket
,如何使代码与Windows兼容?谢谢。
答案 0 :(得分:4)
不幸的是,select
无法帮助您在一个线程中处理stdin
和网络事件,因为select
无法在Windows上使用流。您需要的是一种无阻塞地阅读stdin
的方法。你可以使用:
stdin
的额外帖子。这应该工作正常,是最简单的工作方式。如果您需要的只是等待I / O事件,那么Python线程支持就可以了。twisted
这样的库(请参阅注释)提供非阻塞文件I / O.这种方式是最一致的,但它应该要求使用与您的框架匹配的样式(twisted
或gevent
来编写整个应用程序,差异并不重要)。但是,我怀疑twisted
包装器无法在Windows上stdin
进行异步输入(非常确定它们可以在* nix上执行此操作,因为它们可能使用相同的select
)。答案 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()