/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Ayuda con recv() y send() en sockets

 
      Índice del Foro elrincondelc.com -> Programación en Servidores
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
Moises



Registrado: 21 Oct 2007
Mensajes: 4

MensajePublicado: 21/10/2007 8:27 am
Título: Ayuda con recv() y send() en sockets

Buenas,
Estoy programando una aplicación con sockets para conectar a un servidor pop y tengo un problemilla.

uso send() y recv() de la siguiente manera:
send(sock,comando,tamano,0);
variable=recv(sock,buffer,MAX,0);

El problema es el siguiente:
por lo visto las respuestas del servidor se quedan en un buffer que tengo que ir liberando y se queda pendiente, imaginemos el siguiente caso

Paso comando USER usuario
el me contesta +ok password required, y es este mensaje el que se queda en cola, si con recv() le pongo de tamaño 10, recibire +ok passwor. Hasta ahi bien.
si ahora pongo Pass password y uso recv() recibo: d required.

por que el mensaje anterior no ha podido descargarse entero, aqui no hay problema por que aumento el tamaño de salida. pero para recibir correos ya es peor.

Existe algun parametro u otro procedimiento para realizar esto correctamente, que si no recibo el mensaje, este se descarte?

Como SO uso Linux y el compilador GCC.

Muchas gracias y un saludo.
Volver arriba
Moises



Registrado: 21 Oct 2007
Mensajes: 4

MensajePublicado: 21/10/2007 11:36 pm
Título:

Aqui va una posible solución (o quizas la única). Según me han comentado lo suyo sería meter el recv() en un while hasta vaciar el buffer.

No lo he probado, pero parece que así se soluciona, si alguien sabe de otra forma por favor que lo ponga, ya que solo quiero el primer caracter del buffer y no quiero estar tratando el resto.

Bueno, espero que sirva de ayuda a alguien que le haya pasado lo mismo.

Un saludo.
Volver arriba
cheroky



Registrado: 22 Sep 2005
Mensajes: 1372
Ubicación: En ecx esperando un call

MensajePublicado: 22/10/2007 4:14 am
Título:

No creo que se solucione con un bucle sobre recv, mas bien, y por lo que tengo entendido sobre tu problema necesitas implementarlo sobre sockets no bloqueantes, busca info sobre fcntl.

Otra opción es utilizar hilos.

Por cierto ¿que tamaño usas para el buffer en recv? si puedes postear algo de código mejor.


S2.
_________________
- Explícito es mejor que implícito.
- Simple es mejor que complejo.
- Complejo es mejor que complicado.
- Plano es mejor que anidado.
- Ralo es mejor que denso.
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 316
Ubicación: En la Luna

MensajePublicado: 28/10/2007 8:56 am
Título:

Hola:

Que tal Moises, creo que utilizar funciones fcntl solo te serviria en casos de que el socket vaya a ser utilizado por varias aplicaciones y estas requieran utilizar le mismo socket aunque este siendo utilizado para send() y/o recv(), asi que por mi parte lo descarto..

La solucion que te propongo Moises es cuestion de que resuelvas bien tu problema con el buffer... porque segun entiendo en tu explicacion dices que el servidor POP hace lo siguiente:

1- tu envias: 'USER'
2- el servidor contesta: '+ok password required'
3- posteriormente el servidor sigue enviandote constante mente el mensaje '+ok password required', ya que si haces algun recv() seguiras obteniendo este comando...

Si eso va bien.. entonces el servidor esta loco jejejjee, porke se supone que deberia enviar el COMANDO y espera la recepcion de los datos... En fin, posiblemente el servidor realiza el re-envio de la informacion debido a que no fue capturado todo el comando, te pondre un ejemplo:

1- Servidor envia: '+ok password required\0' (son 21 caracteres, contando de 0-21).
2- Tu realizas un recv() con buffer de 20.. Entonces recives: ' +ok password required', pero falta el Fin de Texto '\0', el servidor checa que los bytes enviados fueron de 20 y NO de 21, entonces vuelve a enviarte los datos.

Para evitar problemas con la transmicion de informacion te explicare basicamente como funciona recv(), ya que tu problema es SIMPLE de solucionar, sencillamente necesitas LEER del buffer hasta que se finalize el BUFFER...

recv() es una funcion que permite leer de un canal de datos, peroe ste se limita el tamano en que se desee leer de dicho buffer... En tu caso, el limite es MAX (tu variable definida).

Como puedes saber si se termino de transmitir ??...
recv() trabaja de la siguiente maneja, la cual nos ayudara a determinar si los datos que se nos envian son recividos por completo, hubo un error o simplemente se perdio la conexion, asi que rev() actua asi (ejemplo simple):

Código:
   do
      {
      memset( &buf, '\0', N ); //limpiamos buffer
      bytes_r=0; //inicializamos

      if( (bytes_r=recv( clientds, buf, N, 0 ))==-1 )
         fprintf( stderr, "\nProblemas para Recivir Datos :: %s", strerror(errno) );
      else
         {
         if( bytes_r==0 )
            {
            printf( "--El Cliente Forzo el Cierre --\n" );
            pthread_exit(0); //salimos del hilo y finalizamos
            }
         else if( bytes_r==-1 )
            {
            printf( "-- El Cliente Salio ---\n" );
            pthread_exit(0); //salimos del hilo y finalizamos
            }
         else
            printf( "%s\n\r", buf );
         }
      }while( bytes_r!=0 && bytes_r!=-1 );


Puedes implementar este codigo que te deje, solo AGREGALE una comparacion mas DENTRO del while() Wink, me imagino que has de saber cual ??

Te lo dejo de tare y comentanos tus resultados Very Happy !!

bye bye
_________________

Volver arriba
Moises



Registrado: 21 Oct 2007
Mensajes: 4

MensajePublicado: 28/10/2007 12:52 pm
Título:

Lo primero es daros las gracias, pero no lo consigo Smile

Lo meto en el bucle tal y como me dices, pero encuentro un problema, cuando el mensaje no es capaz de llenar el buffer se queda pillao y no responde.
Lo he estado depurando y me he dado cuenta de que es eso, incluso si le meto un 1 como numero de caracteres a devolver pasa lo mismo.

Imaginemos que tengo lo que he dicho antes "+ok password required" y le digo que devuelva de 5 en un bucle, haria lo siguiente
+ok p
asswo
rd re
quire
Y aquí se queda bloqueado, segun he leido lo ultimo que contesta el pop es "\r\n" lo he intentado capturar pero no soy capaz, me tiene desesperado
Embarassed . Seguiré intentando a ver si soy capaz de solucionarlo.

Muchas gracias a todos, si a alguien se le ocurre algo.....
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 316
Ubicación: En la Luna

MensajePublicado: 28/10/2007 5:50 pm
Título:

Hola:

Te molestaria poner algo de tu codigo ?

bye bye
_________________

Volver arriba
Moises



Registrado: 21 Oct 2007
Mensajes: 4

MensajePublicado: 29/10/2007 4:21 am
Título:

La verdad es que si que tenia que haber publicado el codigo antes, lo siento, pero el codigo que estoy utilizando es el que me has dado tu antes Smile
Código:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <curses.h>
#include <ctype.h>

#define MAX 1000

int sock, numero_bytes, salir, i;
char buffer[MAX], comando[MAX], c[MAX];
double largo, total;

int main()
{

  char prueba;
  int sock;
  char user[255];
  char pass[255];
  char domain[255];
  int port;
  char comando[255];
  char contador[2];

  int bytes_r;
  int errno;

  salir = 0;
  i = 0;

  //estos datos son correctos en mis prubas, aqui los he omitido
  strcpy(user,"USER usuario");
  strcpy(pass,"PASS password");
  strcpy(domain,".0.0.0.0");
  port = 110;

  sock = socket (AF_INET, SOCK_STREAM, 0);

  if (sock == -1)
    {
      printf ("Error al abrir el Socket\n");
      error(-1);
    }

  struct sockaddr_in Direccion;
  Direccion.sin_family = AF_INET;
  Direccion.sin_addr.s_addr = inet_addr(domain);
  Direccion.sin_port = htons(port);

  if (connect (sock, (struct sockaddr *)&Direccion,sizeof (Direccion)) == -1)
  {
    printf ("Error al conectar a la máquina destino\n");
    exit(-1);
  }
 
   numero_bytes = recv(sock, buffer, MAX, 0);

   if (numero_bytes == -1)
     {
       printf("Error al obtener los datos de la máquina destino");
       exit(-1);
     }
   
   
   //Nos conectamos al servidor
   strcat(user,"\r\n");
   largo = strlen(user);
   send(sock,user,largo,0);
   
   // numero_bytes = recv(sock, buffer, MAX,  MSG_OOB);
   numero_bytes = read(sock,buffer,MAX);
   buffer[numero_bytes] = '\0';
   printf("%s",buffer);
   if (buffer[0]=='+')
     printf("\nUsuario Aceptado");

   strcat(pass,"\r\n");
   largo = strlen(pass);
   send(sock,pass,largo,0);

   
   numero_bytes=read(sock,buffer,MAX);
   buffer[numero_bytes] = '\0';
   printf("%s",buffer);
   if (buffer[0]=='+')
     printf("\nPassword Aceptado");

   
// LO QUE HAGO ES RECIBIR LA CABECERA DEL MENSAJE 1, QUE ES SUPERIOR A 1000BYTES.
   i = 1;
   strcpy(comando,"TOP ");
   largo=sprintf(contador,"%d",i);
   strcat(comando,contador);
   strcat(comando," 1\r\n");
   largo = strlen(comando);
   send(sock,comando,largo,0);

   do
     {
       memset(&buffer,'\0',MAX);
       bytes_r = 0;
       
       if ((bytes_r=recv(sock,buffer,1,0))==-1)    ///<--- AQUI ES DONDE FALLA AL PASAR POR SEGUNDA VEZ
      fprintf(buffer,"\nProblemas para Recibir datos :: %s",sterror(errno));
    else
    {
      if (bytes_r==0)
        {
          printf("--El Cliente forzo del cierre --\n");
          phtread_exit(0);
        }
      else if (bytes_r==-1)
        {
          printf("-- El Cliente salio --\n");
          pthread_exit(0);
        }
      else
        printf("%s\n\r",buffer);
    }
     }while (bytes_r!=0 && bytes_r!=-1);


   close(sock);
 return(0);

}


Seguro que me dejo variables que sobran o cosas parecidas pero es que he omitido parte del codigo que tenia comentado, pero en principio esto no funciona. Se queda al intentar descargar el buffer.

Un saludo y gracias de nuevo
Volver arriba
Diabliyo



Registrado: 14 Abr 2004
Mensajes: 316
Ubicación: En la Luna

MensajePublicado: 04/11/2007 8:00 pm
Título:

Moises escribió:
La verdad es que si que tenia que haber publicado el codigo antes, lo siento, pero el codigo que estoy utilizando es el que me has dado tu antes Smile


Primero pues no entendi eso de: 'estoy utilizando es el que me has dado tu antes Smile'. ??!!... Yo no programo con variables GLOBALES :S !!...

Ahora van mis correcciones:

1- Las variables comando[], salir, i y sock estan repetidas, ya que estan declaradas como GLOBALES (fuera de main) y luego tambien como LOCALES (dentro de main)
2- Los buffers (char algo[]) se deben LIMPIAR antes de utilizarlos, osease rellenarlos de '\0' (fin de texto) siempre.
3- La cosa no era COPY & PASTE, debiste eliminar las funciones para hilos (pthread_exit()).

Aqui esta el codigo corregido, nomas que por ahora no lo puedo compilar debido a que mi LAPTOP esta en la fabrica debido a reparacion, asi que apenas me llegara el MARTES y seria cuando pueda compilar tu code... Mientras trata con este codigo y dime que paso...

Código:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <curses.h>
#include <ctype.h>

#define MAX 1000

int sock, numero_bytes, salir, i;
char buffer[MAX], comando[MAX], c[MAX];
double largo, total;

int main()
   {
   char prueba;
   int sock, port, bytes_r, errno;
   char user[255], pass[255], domain[255], comando[255], contador[2];

   salir = 0;
   i = 0;

   //antes de escribir en un BUFFER debes limpiarlo
   memset( &user, '\0', 255 );
   memset( &pass, '\0', 255 );
   memset( &domain, '\0', 255 );
   memset( &comando, '\0', 255 );
   memset( &contador, '\0', 2 );
   memset( &buffer, '\0', MAX );
   memset( &c, '\0', MAX );

   //estos datos son correctos en mis prubas, aqui los he omitido
   strcpy(user,"USER usuario");
   strcpy(pass,"PASS password");
   strcpy(domain,".0.0.0.0");
   port = 110;

   sock = socket (AF_INET, SOCK_STREAM, 0);

   if (sock == -1)
      {
      printf ("Error al abrir el Socket\n");
      error(-1);
      }

   struct sockaddr_in Direccion;

   Direccion.sin_family = AF_INET;
   Direccion.sin_addr.s_addr = inet_addr(domain);
   Direccion.sin_port = htons(port);

   if (connect (sock, (struct sockaddr *)&Direccion,sizeof (Direccion)) == -1)
      {
      printf ("Error al conectar a la máquina destino\n");
      exit(-1);
      }

   numero_bytes = recv(sock, buffer, MAX, 0);

   if (numero_bytes == -1)
      {
      printf("Error al obtener los datos de la máquina destino");
      exit(-1);
      }

   //Nos conectamos al servidor
   strcat(user,"\r\n");
   largo = strlen(user);
   send(sock,user,largo,0);

   // numero_bytes = recv(sock, buffer, MAX,  MSG_OOB);
   numero_bytes = read(sock,buffer,MAX);
   buffer[numero_bytes] = '\0';
   printf("%s",buffer);

   if (buffer[0]=='+')
      printf("\nUsuario Aceptado");

   strcat(pass,"\r\n");
   largo = strlen(pass);
   send(sock,pass,largo,0);

   numero_bytes=read(sock,buffer,MAX);
   buffer[numero_bytes] = '\0';
   printf("%s",buffer);

   if (buffer[0]=='+')
      printf("\nPassword Aceptado");

   // LO QUE HAGO ES RECIBIR LA CABECERA DEL MENSAJE 1, QUE ES SUPERIOR A 1000BYTES.
   i = 1;
   strcpy(comando,"TOP ");
   largo=sprintf(contador,"%d",i);
   strcat(comando,contador);
   strcat(comando," 1\r\n");
   largo = strlen(comando);
   send(sock,comando,largo,0);

   do
      {
      memset(&buffer,'\0',MAX);
      bytes_r = 0;

      if((bytes_r=recv(sock,buffer,1,0))==-1)    ///<--- AQUI ES DONDE FALLA AL PASAR POR SEGUNDA VEZ
         fprintf(buffer,"\nProblemas para Recibir datos :: %s",sterror(errno));
      else
         {
         if (bytes_r==0)
            printf("--El Cliente forzo del cierre --\n");
   
         else if (bytes_r==-1)
            printf("-- El Cliente salio --\n");
   
         else
            printf("%s\n\r",buffer);
         }
      }while (bytes_r!=0 && bytes_r!=-1);

   close(sock);
   return(0);
   }

_________________

Volver arriba
      Índice del Foro elrincondelc.com -> Programación en Servidores
Página 1 de 1Todas las horas están en GMT - 8 Horas

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com