Jue Nov 22, 2007 12:20 pm
|
 |
rklz
Perlero Nuevo

|
Registrado: 25 May 2007
Mensajes: 38
Ubicación: Rosario, Argentina
|
|
| Socket problema con las respuestas |
|
|
Saludos, les cuento mi problema...
Tengo el siguiente código....
| Perl: | #/usr/bin/perl -w
use strict;
use IO:: Socket;
my @a;
my ($espera, $data, $response, $new_sock, $buf, $leng);
my $host = shift || 'x.x.x.x';
my $port = shift || x;
my $sock = new IO:: Socket:: INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
)
|| die "socket error : $!/n"
;
if ($sock) {
while (1) {
comando ();
$espera = getc(STDIN);
}
}
sub comando {
@a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3
);
foreach (@a) {
print $sock chr($_);
}
print scalar $sock;
} |
La idea es que el cliente éste manda esa secuencia de bytes a un programa que le responde, pero la respuesta jamás llega ..
¿Alguna idea? |
|
|
|

Jue Nov 22, 2007 3:58 pm
|
 |
Jenda
Perlero Frecuente

|
Registrado: 29 Oct 2007
Mensajes: 108
Ubicación: Praga, Republica Checa
|
|
| Re: Socket problema con las respuestas |
|
|
No intentas leer ninguna respuesta.
debe ser
Es posible que haya otros problemas, no lo he testado.
Jenda |
|
Jue Nov 22, 2007 5:30 pm
|
 |
rklz
Perlero Nuevo

|
Registrado: 25 May 2007
Mensajes: 38
Ubicación: Rosario, Argentina
|
|
|
|
|
Ya había probado de esa forma y nada tampoco  |
|
Vie Nov 23, 2007 10:35 am
|
 |
Jenda
Perlero Frecuente

|
Registrado: 29 Oct 2007
Mensajes: 108
Ubicación: Praga, Republica Checa
|
|
| El código me parece OK, ¿qué tal lo que mandas? |
|
|
Si pruebo el código con localhost y port 80, yo obtengo:
| Código: |
| HTTP/1.1 400 Bad Request |
Es exactamente lo que esperaba. ¿Sabes, por cierto, si lo que mandas es correcto y completo? ¿No debe estar acabado por un \n o algo así? |
|
Vie Nov 23, 2007 2:59 pm
|
 |
creating021
Vive para Perl en Español

|
Registrado: 23 Feb 2006
Mensajes: 498
Ubicación: Frente al monitor
|
|
|
|
|
| Cita: | La idea es que el cliente éste manda esa secuencia de bytes a un programa que le responde, pero la respuesta jamás llega ... |
¿Cómo estás esperando la respuesta? En ninguna parte de ese código está escuchando al servidor.
Si realmente crees que el servidor es el que no escucha, trata de usar la función send (de IO::Socket, lee los manuales) aunque creo que el problema está en el cliente. |
|

Vie Nov 23, 2007 3:39 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4232
Ubicación: Valladolid, España
|
|
|
|
|
Quizás pasa lo que dice Jenda: que el servidor no sabe cuándo ha terminado de recibirlo todo...
Si yo creo un servidor que esté preparado para recibir bloques de 62 bytes (el tamaño del array @a) entonces sí que funciona:
servidor:
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
my $sock = new IO:: Socket:: INET(
LocalHost => 'localhost',
LocalPort => 7890,
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1);
$sock or die "no socket :$!";
STDOUT-> autoflush(1);
my($new_sock, $buf);
while ($new_sock = $sock-> accept()) {
read $new_sock, $buf, 62;
print ord($_), " " foreach split //, $buf;
print "\n";
print $new_sock "ENVIADO!\n";
close $new_sock;
} |
cliente:
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
my $sock = new IO:: Socket:: INET(
PeerAddr => 'localhost',
PeerPort => 7890,
Proto => 'tcp');
$sock or die "no socket :$!";
my @a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3
);
print "Enviando ", scalar @a, " elementos\n";
foreach (@a) {
print $sock chr($_);
}
print scalar < $sock>; # Respuesta del servidor
close $sock; | Arrancamos el servidor en una terminal, y el cliente en otra. En la del servidor aparecen la ristra de bytes y queda esperando para la siguiente. En la del cliente, aparece el indicativo de que sí han sido enviados y recibidos por el servidor. Pero esto lo podemos hacer porque el servidor sabe exáctamente que tiene que leer solo 62 bytes antes de continuar con el programa. No está contemplado otro caso, como por ejemplo que la longitud sea distinta o que la comunicación se corte a la mitad.
Viendo la lista de bytes, se nota que hay muchas minúsculas, así que se trata de un texto, junto con otros valores en binario. De todos los valores, el que me llama la atención es el segundo: está indicando la longitud de los datos que le siguen.
Supongamos que el protocolo es ese: el bloque de datos comienza con un 1 y le sigue un byte que indica lo que le sigue. El servidor sabe entonces cuánta información debe leer.
Con este nuevo servidor:
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
my $sock = new IO:: Socket:: INET(
LocalHost => 'localhost',
LocalPort => 7890,
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1);
$sock or die "no socket :$!";
STDOUT-> autoflush(1);
my($new_sock, $buf);
while ($new_sock = $sock-> accept()) {
$buf = getc $new_sock; # Leemos el primer byte
if ( $buf eq "\1" ) {
print "Recibido inicio de paquete\n";
my $longitud = 1 + ord getc $new_sock; # Esperar la llegada de la longitud
print "Recibiendo $longitud bytes\n";
read $new_sock, $buf, $longitud; # Leemos esa cantidad
my ($h1, $h2, $texto, $crc) # Desempaquetado
= unpack("H8 H8 Z* H4", $buf);
print "$h1,$h2\n";
print "Texto:$texto.\n";
print "$crc\n";
print $new_sock "ENVIADO!\n";
}
} | y ahora el nuevo cliente:
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
my $sock = new IO:: Socket:: INET(
PeerAddr => 'localhost',
PeerPort => 7890,
Proto => 'tcp');
$sock or die "no socket :$!";
my $texto = '1.2b,Movistar,internet.gprs.unifon.com.ar,wap,wap';
print $sock "\1"; # Cabecera
print $sock chr(length($texto)+ 1+ 8+ 2- 1); # uno menos
print $sock chr $_ foreach ( 0xa0, 0x01, 0x01, 0x01, 0xa0, 0x01, 0x01, 0x14 ); # 8
print $sock "$texto\0"; # 50
print $sock chr 0x22, chr 0x03; # 2
print scalar < $sock>; # Respuesta del servidor
close $sock; | obtenemos la misma respuesta, pero ahora el servidor ya está preparado para recibir otros textos con distinta longitud, y el cliente está modificado para ser fácil enviar otros textos.
Notar la facilidad de unpack en el servidor. Queda como ejercicio hacer lo mismo en la parte del cliente, para dejarlo incluso más sencillo.
(Movistar, ¿eh? )
Imprescindible ver la página de Linux Journal sobre Networking.
Ultima edición por explorer el Sab Jun 21, 2008 3:25 pm, editado 1 vez |
|

Lun Nov 26, 2007 1:02 pm
|
 |
rklz
Perlero Nuevo

|
Registrado: 25 May 2007
Mensajes: 38
Ubicación: Rosario, Argentina
|
|
|
|
|
Gracias a los 2 por tomarse el tiempo y revisar mi código , les cuento lo siguiente:
jenda dice que con este código:
| Perl: | #/usr/bin/perl -w
use strict;
use IO:: Socket;
my @a;
my ($espera, $data, $response, $new_sock, $buf, $leng);
my $host = shift || 'x.x.x.x';
my $port = shift || x;
my $sock = new IO:: Socket:: INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
)
|| die "socket error : $!/n"
;
if ($sock) {
while (1) {
comando ();
$espera = getc(STDIN);
}
}
sub comando {
@a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3
);
foreach (@a) {
print $sock chr($_);
}
print scalar < $sock>;
} |
obtiene una respuesta del servidor HTTP, pero yo intento lanzar el código contra un servidor HTTP que está corriendo y funcionando, y me pasa lo mismo: conecta, pero no obtengo ninguna respuesta , no sé qué es lo que estará pasando...
Y gracias explorer por revisar el post y armar esos códigos, pero te cuento que el servidor, no lo hago yo, el servidor lo tiene hecho mi jefe, en .net sobre Windows XP y teóricamente con solamente mandar esa cadena de bytes devuelve la respuesta; es por eso que no entiendo por qué nunca me llega, o por lo menos no se vuelca en la pantalla.
Otra de las cosas es que hicimos pruebas con mi jefe y pudimos ver que a él le llega correctamente la cadena de bytes, y me manda la respuesta, no hay error hasta ahí, entonces el problema está en mi código, pero no sé por qué
¡Ayuda! |
|

Lun Nov 26, 2007 4:27 pm
|
 |
Jenda
Perlero Frecuente

|
Registrado: 29 Oct 2007
Mensajes: 108
Ubicación: Praga, Republica Checa
|
|
|
|
|
Este
debe ser
¿Cómo es la respuesta? ¿Tiene más líneas? Prueba a cambiar el último print a
| Perl: | print "RESPONSE\n", < $sock>, "\n/RESPONSE\n\n"; |
|
|
Lun Nov 26, 2007 5:14 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4232
Ubicación: Valladolid, España
|
|
|
|
|
¿Y no será que sí que recibes la respuesta pero como no tiene un retorno de carro el programa no sabe que ha terminado de llegar?
¿Cómo es la respuesta? ¿De un tamaño fijo? En ese caso usa read.
Activa el autoflush.
No me importa cómo sea el programa servidor del jefe. Lo importante es saber perfectamente el protocolo. De ahí, lo que queda es que los dos programas se comporten bien. |
|

Lun Nov 26, 2007 7:38 pm
|
 |
rklz
Perlero Nuevo

|
Registrado: 25 May 2007
Mensajes: 38
Ubicación: Rosario, Argentina
|
|
|
|
|
Pruebo con este código :
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
STDOUT-> autoflush(1);
my @a;
my ($espera, $data, $response, $new_sock, $buf, $leng);
my $host = shift || 'x.x.x.x';
my $port = shift || x;
my $sock = new IO:: Socket:: INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
)
|| die "socket error : $!/n"
;
if ($sock) {
while (1) {
comando ();
# $espera = getc(STDIN);
}
}
sub comando {
@a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3
);
foreach (@a) {
print $sock chr($_);
}
print "RESPONSE\n", < $sock>, "\n/RESPONSE\n\n";
} |
y nadaaaa
Tiene que haber algún tipo de error, porque lo estoy usando contra el servidor de una página web, obviamente puerto 80, que está funcionando, y con telnet responde, pero el programa sigue haciendo lo mismo, se ejecuta y queda ahí, nunca se ve nada en pantalla ni se aborta inesperadamente, ¡¡¡simplemente se queda ahí!!! |
|

Mar Nov 27, 2007 4:30 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4232
Ubicación: Valladolid, España
|
|
|
|
|
El problema es el siguiente: un servidor web 'normal' espera recibir una cadena de texto terminada en un retorno de carro; y tu, lo que envías es un string con partes en binario y NO envías el carácter de final de línea, por lo que el servidor web no responderá porque todavía no ha terminado de recibir el mensaje completo.
Si en la línea del @a agregas al final el valor 10 (carácter de nueva línea) entonces sí que responderá el servidor web:
Con el siguiente programa:
| Perl: | #!/usr/bin/perl -w
use strict;
use IO:: Socket;
$|++;
my @a;
my ($espera, $data, $response, $new_sock, $buf, $leng);
my $host = shift || 'w3desa01';
my $port = shift || 80;
my $sock = new IO:: Socket:: INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
)
|| die "socket error : $!/n"
;
$sock-> autoflush(1);
if ($sock) {
# while (1) {
comando ();
# $espera = getc(STDIN);
# }
}
sub comando {
@a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3, 10
);
print "Enviando...\n";
foreach (@a) {
print $sock chr($_);
}
# while ($sock) {
print "RESPONSE:", < $sock>, "\n/RESPONSE\n\n";
# }
}
__END__ | obtenemos la siguiente salida:
| Código: |
$ ./kk.pl
Enviando...
RESPONSE:HTTP/1.1 400 Bad Request
Date: Tue, 27 Nov 2007 10:17:52 GMT
Server: Apache/1.3.33 (Win32) mod_perl/1.29_01-dev mod_ssl/2.8.22 OpenSSL/0.9.7f PHP/4.3.9
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>400 Bad Request</TITLE>
</HEAD><BODY>
<H1>Bad Request</H1>
Your browser sent a request that this server could not understand.<P>
The request line contained invalid characters following the protocol string.<P>
<P>
<HR>
<ADDRESS>Apache/1.3.33 Server at w3desa01 Port 80</ADDRESS>
</BODY></HTML>
/RESPONSE |
Es decir, el servidor web sí que ha respondido porque ha recibido una carácter de fin de línea. Lo malo es que no sabe responder al galimatías que le hemos mandado.
Como he dicho antes, todo depende del protocolo.
En un mensaje anterior has dicho que desde el programa del jefe se sabe que se ha recibido correctamente y que éste ha respondido.
Lo que pasa es que, seguramente, el mensaje del jefe no manda un carácter de final de línea como que el operador <$sock> está esperando. Y por eso se queda ahí, esperando ese carácter que nunca llega.
Debes hacer una de estas dos cosas: si el mensaje de respuesta del jefe es de un tamaño fijo, usa la función read(). Si el mensaje no es de tamaño fijo, deberás leerlo de otra manera. Por ejemplo, con getc():
Con estas líneas puedo leer todos los bytes que me van llegando, hasta que el servidor corta la conexión. Les saco a pantalla, pero podría guardarles en un buffer, escribir a un fichero, etc.
Lo he probado con el mismo servidor web y he obtenido la misma salida de antes (lógico, porque el servidor web sí que me manda caracteres de final de línea). |
|

Mar Nov 27, 2007 10:05 pm
|
 |
rklz
Perlero Nuevo

|
Registrado: 25 May 2007
Mensajes: 38
Ubicación: Rosario, Argentina
|
|
|
|
|
Bueno, resulta que estoy probando las cosas desde mi casa en Windows, mediante PuTTY conectado a los servidores de la empresa , probando este código:
| Perl: |
#!/usr/bin/perl -w
use strict;
use IO:: Socket;
STDOUT-> autoflush(1);
my @a;
my ($espera, $data, $response, $new_sock, $buf, $leng);
my $host = shift || x.x.x.x;
my $port = shift || x;
my $sock = new IO:: Socket:: INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
)
|| die "socket error : $!/n"
;
if ($sock) {
while (1) {
comando ();
$espera = getc(STDIN);
}
}
sub comando {
@a = ( 1, 59, 160, 1, 1, 1, 160, 1, 1, 20, 49, 46, 50, 98, 44, 77,
111, 118, 105, 115, 116, 97, 114, 44, 105, 110, 116, 101, 114, 110, 101, 116,
46, 103, 112, 114, 115, 46, 117, 110, 105, 102, 111, 110, 46, 99, 111, 109,
46, 97, 114, 44, 119, 97, 112, 44, 119, 97, 112, 0, 34, 3
);
foreach (@a) {
print $sock chr($_);
}
while (defined ($_ = getc $sock)) {
print $_;
}
} |
la salida textual es :
®§PuTTYPuTTY
jajajaja es muuuuy raro xD
PD: Agregando el 10 al final de los bytes, probando contra la página web funcioná bien
EDIT :
Agregando la función ord() en esta:
parte del código, obtuve el resultado que quería (creo ): una cadena de bytes, que me falta corroborar para ver si es la correcta, pero creería que sí. Muchas gracias a todos por las ayudas
PD2 : Explorer, una preguntita, ¿qué es la variable $|++, que definiste al principio de tu programa? |
|

Mie Nov 28, 2007 3:04 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4232
Ubicación: Valladolid, España
|
|
|
|
|
El necesitar ord() o no depende de lo que quieras hacer después con la información recibida.
$| es una variable especial. Está descrita en perlvar. Es el autoflush para la salida estándar. |
|
Powered by phpBB © 2001, 2005 phpBB Group
|