我正在使用这里的代码testingUDP冲孔。 它在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]
是什么意思? 这是一种经常使用的技术吗? select
只适用于Windows上的socket
,如何使代码Windows兼容? 谢谢。
不幸的是, select
不会帮助您在一个线程中处理stdin
和网络事件,因为select
不能在Windows上使用流。 你需要的是一种无阻塞地读取stdin
的方法。 您可以使用:
stdin
的额外线程。 这应该工作得很好,是做这份工作最简单的方法。 如果你需要的只是等待I / O事件,那么Python线程支持是相当好的。 twisted
库(见注释)提供非阻塞文件I / O。 这种方法是最一致的,但是它应该要求使用与你的框架相匹配的风格来编写整个应用程序( twisted
或gevent
,差异不显着)。 但是,我怀疑twisted
包装不能从Windows上的stdin
输入异步输入(相当肯定他们可以做* nix,因为他们可能使用相同的select
)。 正如答案所暗示的,我创建了另一个线程来处理输入流并且工作。 这是修改的代码:
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()
我的答案是在同一时间的问题:我发现一个telnet.py在网络上由以下代码实现:
# telnet program example in python (2.7.x) import socket, select, string, sys #main function if __name__ == "__main__": if(len(sys.argv) < 3) : print 'Usage : python telnet.py hostname port' sys.exit() host = sys.argv[1] port = int(sys.argv[2]) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(2) # connect to remote host try : s.connect((host, port)) except : print 'Unable to connect' sys.exit() print 'Connected to remote host' while 1: socket_list = [sys.stdin, s] print socket_list; # Get the list sockets which are readable read_sockets, write_sockets, error_sockets = select.select(socket_list , [], []) for sock in read_sockets: #incoming message from remote server if sock == s: data = sock.recv(4096) if not data : print 'Connection closed' sys.exit() else : #print data sys.stdout.write(data) #user entered a message else : msg = sys.stdin.readline() s.send(msg)# telnet program example
奇怪的是,这个代码在Windows下无法运行(因为在Windows Winsock2实现中,select不能在stdin FD上运行)
建议的解决方案是指UDP示例,它看起来结构有点不同。 有人知道解决方案将上面的telnet.py转换为线程操作?
谢谢。