2011-04-08 21 views
5

Estoy tratando de trabajar en un pequeño proyecto de aprendizaje de Perl que requiere leer 4 enteros sin signo de un socket. No pude leer más de 1 entero, y después de buscar descubrí una solución. Pero tengo que entender lo que no hice derechasocket-> recv() vs. <>?

Ejemplo 1 (y han pasado por un par de libros de Perl, perldocs, etc en vano.): Aquí está el código de la solución exitosa (original), asumir la socket connect es exitoso para ambos a continuación:

{ 
    local $/ = \16; # make <> read in 16 bytes with one swoop. 
    my @integers = unpack "IIII", <$sock>; 
    print "numbers: @val\n"; 
} 

Ejemplo 2: Intenté esto a continuación. Si puedo imprimir la entrada antes de desembalar, solo me dan un entero:

my $input; 
$sock->recv($input,16,0); 
my @integers = unpack("IIII", $input); 

preguntas específicas:

  1. En el ejemplo 1, ¿qué diablos es "$ /"? ¿Y cómo "cambia" <>, lo que pensé, leí STDIN?
  2. En el ejemplo 2, ¿hay alguna razón por la cual mi recv() no extraiga más de un entero del socket? Mi comprensión (por perldoc) es que el parámetro "SIZE" se predetermina a "bytes", y los enteros son 4 bytes?

Se agradece cualquier ayuda, sugerencias, etc. Por cierto, el "proyecto de aprendizaje" es overthewire.org - cosas geniales.

+1

Para que la documentación simple salga del camino: [perlvar $ /] (http://p3rl.org/var#%24INPUT_RECORD_SEPARATOR); '<>' es solo un nombre diferente para [readline] (http://p3rl.org/readline) – daxim

Respuesta

1

En cuanto a 1)

Bueno, <> toma cualquier controladores de archivo, incluyendo los zócalos. Es una convención que puede dejarla en blanco, en cuyo caso se asume un cierto tipo de comportamiento predeterminado. Consulte perldoc perlop (busque <> en el interior).

Y la variable especial $/ es separador de registros y su valor predeterminado es "\ n". Puedes descifrarlo y leer todo el archivo a la vez (eso se llama sorber). Vea perldoc perlvar para más información (el caso \number también está allí).

+0

Esto funcionó para mí, aunque utilicé todos los comentarios. Nunca pude leer/readline/recv para trabajar. Pero ahora que entiendo cómo usar <> y $ /, me siento cómodo moviéndome. Gracias por la ayuda. – 1111000110

4

¿Su socket es TCP o UDP?

recv es una rutina de nivel inferior que <>/readline. Se asigna más o menos directamente a la llamada al sistema recv(2). Si los datos del socket llegan como 4 paquetes de 4 bytes, recv volverá inmediatamente una vez que vea el primer paquete, incluso si se le ha suministrado un buffer más grande. Si los 4 paquetes llegan antes de la primera llamada al recv(), entonces si obtiene todos los datos o solo una pieza probablemente depende de si es TCP o UDP.

Si está utilizando TCP, existe la posibilidad de que los paquetes se fragmenten durante el vuelo. Es poco probable que ocurra con cargas útiles de 16 bytes, pero la mejor práctica sería no asumir que se mostrarán 16 bytes de datos a la vez, incluso si sabe que el servidor lo envió todo a la vez. Generalmente, se espera que las aplicaciones de red almacenen en búfer los datos entrantes, o bien, puede hacer que Perl lo haga por usted especificando registros de 16 bytes con $/ = \16.

Otra posibilidad, que me parece más natural que <> para este tipo de uso de I/O, es utilizar el read o sysread funciones (o los equivalentes OO, que se definen en las IO::Socket superclase IO::Handle).Esos toman un argumento de longitud, pero como antes, no debe suponer que todo el buffer se llenará a la vez.

1

read y readline (aka <>) espere a que la cantidad solicitada de caracteres esté disponible antes de volver. Solo devolverá menos caracteres en caso de error o EOF, en cuyo caso la próxima lectura arrojará un error o EOF.

sysread regresa tan pronto como haya algunos caracteres disponibles, incluso si hay menos de la cantidad solicitada.

Según lo que dices, recv es como sysread. Si desea 16 caracteres, deberá hacer un ciclo hasta que tenga 16 caracteres o usar read o readline.