I'm testing UDP punching using code from here. It works on Linux however reports error on Windows. Here's the code snippet where the error occurs:
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)
And error msg:
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, '')
I know this error has some thing to do with the select
implementation on Windows, and everyone quote this:
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.
So I got two questions:
0
in [0, sockfd]
mean? Is this some sort often-used technique? select
only works with socket
on Windows, How to make the code Windows compatible?Thank you.
Python's select() function is a direct interface to the underlying operating system implementation. It monitors sockets, open files, and pipes (anything with a fileno() method that returns a valid file descriptor) until they become readable or writable, or a communication error occurs.
This select module, shown in Example 7-6, allows you to check for incoming data on one or more sockets, pipes, or other compatible stream objects.
select() only uses (at maximum) three bits of data per file descriptor, while poll() typically uses 64 bits per file descriptor. In each syscall invoke poll() thus needs to copy a lot more over to kernel space.
Unfortunately, select
will not help you to process stdin
and network events in one thread, as select
can't work with streams on Windows. What you need is a way to read stdin
without blocking. You may use:
stdin
. That should work fine and be the easiest way to do the job. Python threads support is quite ok if what you need is just waiting for I/O events.twisted
(see the comments) that offer non-blocking file I/O. This way is the most consistent one, but it should require to write the whole application using a style that matches your framework (twisted
or gevent
, the difference is not significant). However, I suspect twisted
wrappers are not capable of async input from stdin
on Windows (quite sure they can do that on *nix, as probably they use the same select
).As the answer suggests, I create another thread to handle input stream and it works. Here's the modified code:
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With