with socket metodo español create con python sockets nonblocking recv

metodo - ¿Qué devuelve socket.recv() de Python para enchufes sin bloqueo si no se reciben datos hasta que se agote el tiempo de espera?



socket python 3 español (4)

Cuando utiliza recv en conexión con, select si el socket está listo para leer, pero no hay datos para leer, lo que significa que el cliente ha cerrado la conexión.

Aquí hay un código que maneja esto, también tenga en cuenta la excepción que se produce cuando se llama a recv segunda vez en el ciclo while. Si no queda nada por leer, se lanzará esta excepción, no significa que el cliente haya cerrado la conexión:

def listenToSockets(self): while True: changed_sockets = self.currentSockets ready_to_read, ready_to_write, in_error = select.select(changed_sockets, [], [], 0.1) for s in ready_to_read: if s == self.serverSocket: self.acceptNewConnection(s) else: self.readDataFromSocket(s)

Y la función que recibe los datos:

def readDataFromSocket(self, socket): data = '''' buffer = '''' try: while True: data = socket.recv(4096) if not data: break buffer += data except error, (errorCode,message): # error 10035 is no data available, it is non-fatal if errorCode != 10035: print ''socket.error - (''+str(errorCode)+'') '' + message if data: print ''received ''+ buffer else: print ''disconnected''

Básicamente, he leído en varios lugares que socket.recv() devolverá cualquier cosa que pueda leer, o una cadena vacía que socket.recv() que el otro lado se ha apagado (los documentos oficiales ni siquiera mencionan qué devuelve cuando la conexión es cerrar ... ¡genial!). Esto está muy bien para las tomas de bloqueo, ya que sabemos que recv() solo regresa cuando realmente hay algo que recibir, así que cuando devuelve una cadena vacía, DEBE significar que el otro lado ha cerrado la conexión, ¿verdad?

Bien, bien, pero ¿qué pasa cuando mi socket no bloquea? He buscado un poco (tal vez no lo suficiente, ¿quién sabe?) Y no puedo entender cómo saber cuándo el otro lado ha cerrado la conexión con un socket sin bloqueo. Parece que no hay ningún método o atributo que nos diga esto, y comparar el valor de retorno de recv() con la cadena vacía parece absolutamente inútil ... ¿es solo que yo tengo este problema?

Como un ejemplo simple, digamos que el tiempo de espera de mi socket está establecido en 1.2342342 (el número no negativo que quiera aquí) segundos y llamo socket.recv(1024) , pero el otro lado no envía nada durante ese segundo período 1.2342342. La llamada a recv() devolverá una cadena vacía y no tengo ni idea de si la conexión sigue en pie o no ...


En el caso de un socket sin bloqueo que no tenga datos disponibles, recv emitirá la excepción socket.error y el valor de la excepción tendrá el error de EAGAIN o EWOULDBLOCK. Ejemplo:

import sys import socket import fcntl, os import errno from time import sleep s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((''127.0.0.1'',9999)) fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK) while True: try: msg = s.recv(4096) except socket.error, e: err = e.args[0] if err == errno.EAGAIN or err == errno.EWOULDBLOCK: sleep(1) print ''No data available'' continue else: # a "real" error occurred print e sys.exit(1) else: # got a message, do something :)

La situación es un poco diferente en el caso en que haya habilitado el comportamiento sin bloqueo a través de un tiempo de espera con socket.settimeout(n) o socket.setblocking(False) . En este caso, socket.error aún está activo, pero en el caso de un tiempo de espera, el valor que acompaña a la excepción siempre es una cadena establecida en ''timed out''. Entonces, para manejar este caso, puede hacer:

import sys import socket from time import sleep s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((''127.0.0.1'',9999)) s.settimeout(2) while True: try: msg = s.recv(4096) except socket.timeout, e: err = e.args[0] # this next if/else is a bit redundant, but illustrates how the # timeout exception is setup if err == ''timed out'': sleep(1) print ''recv timed out, retry later'' continue else: print e sys.exit(1) except socket.error, e: # Something else happened, handle error, exit, etc. print e sys.exit(1) else: if len(msg) == 0: print ''orderly shutdown on server end'' sys.exit(0) else: # got a message do something :)

Como se indica en los comentarios, esta es también una solución más portátil, ya que no depende de la funcionalidad específica del sistema operativo para poner el zócalo en modo sin bloqueo.

Ver recv(2) y el socket python para más detalles.


Es simple: si recv() devuelve 0 bytes; no recibirás más datos sobre esta conexión. Nunca. Aún puede ser capaz de enviar.

Significa que su socket no bloqueante debe generar una excepción (puede depender del sistema) si no hay datos disponibles pero la conexión sigue activa (el otro extremo puede enviar).


Solo para completar las respuestas existentes, sugeriría usar select sockets en lugar de no bloqueadores . El punto es que los sockets no bloqueantes complican las cosas (excepto quizás el envío), así que diría que no hay ninguna razón para usarlos. Si regularmente tienes el problema de que tu aplicación está bloqueada esperando por IO, también consideraría hacer el IO en un hilo separado en segundo plano.