python select.select () en Windows

Estoy probando el punzonado UDP usando código de aquí . Funciona en Linux sin embargo los informes de error en Windows. Aquí está el fragmento de código donde se produce el error:

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) 

Y el mensaje de error:

 Traceback (most recent call last): File "udp_punch_client.py", line 64, in  main() File "udp_punch_client.py", line 50, in main rfds, _, _ = select([0, sockfd], [], []) select.error: (10038, '') 

Sé que este error tiene algo que ver con la implementación select en Windows, y todos citan esto:

Nota Los objetos de archivo en Windows no son aceptables, pero los sockets sí lo son. En Windows, la función de selección () subyacente es proporcionada por la biblioteca de WinSock, y no maneja descriptores de archivos que no se originan en WinSock.

Así que tengo dos preguntas:

  1. ¿Qué significa 0 en [0, sockfd] ? ¿Es esta una técnica de uso frecuente?
  2. Si select solo funciona con socket en Windows, ¿cómo hacer que el código sea compatible con Windows?

Gracias.

Desafortunadamente, select no lo ayudará a procesar eventos stdin y de red en un solo hilo, ya que select no puede funcionar con streams en Windows. Lo que necesitas es una manera de leer stdin sin bloquear. Puedes utilizar:

  1. Un hilo extra para stdin . Eso debería funcionar bien y ser la forma más fácil de hacer el trabajo. El soporte de hilos de Python está bastante bien si lo que necesita es simplemente esperar por eventos de E / S.
  2. Un mecanismo similar a un greenlet como en gevent que parchea los hilos y la mayoría de las funciones de E / S de la biblioteca estándar para evitar que bloqueen los greenlets. También hay bibliotecas como twisted (ver los comentarios) que ofrecen E / S de archivos no bloqueantes. Esta es la forma más consistente, pero debería requerir escribir toda la aplicación utilizando un estilo que coincida con su marco ( twisted o gevent , la diferencia no es significativa). Sin embargo, sospecho que los envoltorios twisted no son capaces de realizar una entrada asíncrona desde la entrada stdin en Windows (bastante seguro de que pueden hacerlo en * nix, ya que probablemente usan la misma select ).
  3. Algún otro truco. Sin embargo, la mayoría de los trucos posibles son bastante feos.

Como sugiere la respuesta, creo otro hilo para manejar el flujo de entrada y funciona. Aquí está el código modificado:

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