2011-01-26 25 views
5

Estoy revisando los documentos y los howtos que encuentro sobre el uso correcto de IO :: Select en términos de comunicaciones de socket de red. Creo que tengo la cabeza alrededor de la mayor parte.¿Cómo hago el correcto manejo de errores IO :: Select?

Sin embargo, todavía estoy un poco confuso sobre el manejo correcto de errores. Supongamos que tengo algo similar al siguiente código que se ejecuta dentro de un objeto. Sí, me doy cuenta de que es complicado, debería integrar IO :: Select en el objeto y no el socket fh en sí mismo, no debería recrear el IO :: Select cada vez que pasa el ciclo, estoy iterando sobre lo que solo puedo ser un único identificador de archivo devuelto, etc. Sin embargo, esto mantiene el ejemplo simple.

Esto es solo un cliente que se conecta a un servidor, pero que quiero ser capaz de manejar adecuadamente los errores de nivel de red como la pérdida de paquetes.

Edit: $self->sock() devuelve solo un socket IO :: Socket :: INET abierto.

sub read { 
    my $self = shift; 
    my($length) = @_; ### Number of bytes to read from the socket 

    my $ret; 

    while (length($ret) < $length) { 
     my $str; 

     use IO::Select; 
     my $sel = IO::Select->new($self->sock()); 

     if (my @ready = $sel->can_read(5)) { ### 5 sec timeout 
      for my $fh (@ready) { 
      my $recv_ret = $fh->recv($str, $length - length($ret)); 
      if (!defined $recv_ret) { 
       MyApp::Exception->throw(
       message => "connection closed by remote host: $!", 
      ); 
      } 
      } 
     } 
     else { 
      ### Nothing ready... we timed out! 
      MyApp::Exception->throw(
        message => "no response from remote host", 
      ); 
     } 
     $ret .= $str; 
     } 

     return $ret; 
} 
  • ¿Es necesario estar marcando la vuelta de recv, o son errores que afectarían que va a aparecer en el IO :: Seleccionar objeto?
  • ¿Manejo correctamente los tiempos de espera, o mi lógica está mal configurada?
  • IO :: Socket hace mención de una excepción existente en un socket filehandle, para errores fuera de banda y otros problemas. ¿Debo verificar esto en caso de un tiempo de espera? ¿Cómo? ¿O no es importante y está bien ignorarlo?
  • ¿Hay algún otro caso de excepción que deba manejar para un comportamiento correcto?
+0

¿Por qué esperas reunir una "longitud mínima" de datos? Y si sock() devuelve una matriz de manejadores de archivos, obtendrá una combinación de respuestas de todos los sockets en orden aleatorio, ¿está bien? – Dallaylaen

+0

Espero recopilar una cantidad mínima de datos porque este host remoto responde a un comando. En lugar de cambiar todo el búfer, estoy cambiando de un byte para determinar la longitud del siguiente fragmento, un fragmento, y continuar hasta que termine la codificación de comunicación. – Oesor

Respuesta

1

1) Lo comprobaría por si acaso. Cuando se trata de seleccionar (2), defensive programming es tu amigo.

2) Supongamos que necesita 2048 bytes y el host remoto envía un byte cada 5 segundos. Acabas de colgar durante 10K segundos = 3 horas. ¿Es eso lo que quieres?

Yo usaría alarm 5 y $SIG{ALRM} = sub {$stop = 1;} en su lugar.

3 y 4) Desde mi experiencia, solo read() while select() hace el trabajo, pero no puedo darle una respuesta segura aquí.

+0

2) El host remoto debería enviar todos los bytes que necesito como una sola comunicación, por lo que esto no debería aplicarse. De hecho, estoy usando una alarma lanzando una excepción actualmente, que funciona; registra y arroja excepciones de tiempo de espera, pero estoy tratando de solucionar un bloqueo intermitente. – Oesor

+0

Si necesita una sola comunicación, ¿por qué usar loop en absoluto? O bien obtienes bytes '$ length', o no. – Dallaylaen

+0

¿Porque puede ser fragmentado? Los paquetes pueden caer? Si estoy esperando 10k caracteres, espero hasta que el socket esté listo para leer, y trato de leer 10k, y solo obtengo un paquete de 1.5k caracteres, necesito esperar para ver si llegan más paquetes y lo vuelvo a leer, no lo haga t yo? – Oesor