Hack x Crack - Comunidad de Seguridad informática

Programación => C / C++ => Mensaje iniciado por: grimoire en Enero 17, 2015, 04:11:21 am

Título: no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: grimoire en Enero 17, 2015, 04:11:21 am
hola

Tengo un problema, estoy tratando de desarrollar un programa de transferencia de archivos pero no logro hacerlo funcionar, tenía entendido que para hacer transferencia se debía abrir el archivo, leer los bytes, guardarlos, convertirlos en algo entendible para el network, después se hacia un intercambio de información, uno manda la cantidad total de bytes del archivo, otro crea un archivo y guarda el total de bytes, y el otro comienza a enviar los bytes leídos, cuando esos bytes igualan a los bytes enviados previamente, el archivo se considera completo y se cierra

el problema es que no puedo enviar el total de bytes que pesa el archivo para guardar la información y que comience la transferencia, ya intente como cuanta forma me encontré googleando pero nada, espero me puedan ayudar

una cosa que note, es que funciona mejor si lo compilo en 32bits con -m32, sino me aparece un error ("violación de segmento")

les dejo el código

CLIENTE

Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <netdb.h>
  6. #include <sys/types.h>
  7. #include <netinet/in.h>
  8. #include <sys/socket.h>
  9.  
  10. int main(){
  11.  
  12. int soc;
  13. uint32_t longbites;
  14. uint32_t buff;
  15. struct sockaddr_in cl;
  16. struct hostent *hos;
  17.  
  18. hos = gethostbyname("127.0.0.1");
  19.  
  20. soc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  21.  
  22. cl.sin_family = AF_INET;
  23. cl.sin_addr = *((struct in_addr*) hos->h_addr);
  24. cl.sin_port = htons(1234);
  25. bzero(&(cl.sin_zero),8);
  26.  
  27. while(connect(soc, (struct sockaddr*)&cl, sizeof(struct sockaddr)) < 0){
  28. printf("error en conexion\n");
  29. exit(1);
  30. }
  31.  
  32. recv(soc, &buff, sizeof(uint32_t), 0);
  33. longbites = ntohl(buff);
  34.  
  35. printf("%ld", longbites);
  36.  
  37. }
  38.  

SERVIDOR

Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <netdb.h>
  6. #include <sys/types.h>
  7. #include <netinet/in.h>
  8. #include <sys/socket.h>
  9.  
  10. int main(){
  11.  
  12.  struct sockaddr_in sv;
  13.  int so, n_so, libnd = 1;
  14.  int siz;
  15.  uint32_t longsize;
  16.  int sin_size;
  17.  
  18.  sin_size = sizeof(struct sockaddr_in);
  19.  
  20.  so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  21.  
  22.  sv.sin_family = AF_INET;
  23.  sv.sin_addr.s_addr = INADDR_ANY;
  24.  sv.sin_port = htons(1234);
  25.  bzero(&(sv.sin_zero),8);
  26.  
  27.  if(setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &libnd, sizeof(int)) == -1){
  28.     perror("setsockopt");
  29.     exit(1);
  30.   }
  31.  
  32.  if(bind(so, (struct sockaddr*)&sv,sin_size) < 0){
  33.  
  34.   printf("error bind");
  35.   exit(1);
  36.   }
  37.  
  38.  if(listen(so, 2) < 0){
  39.  
  40.    printf("error listen");
  41.    exit(1);
  42.   }
  43.  
  44.  if(n_so = accept(so, (struct sockaddr*)&sv, &sin_size) < 0){
  45.  
  46.   perror("error");
  47.   exit(1);
  48.   }
  49.  
  50.  
  51.   FILE * fd = fopen("/home/linux/Vocabulario.pdf", "r");
  52.   fseek(fd, 0, SEEK_END);
  53.   siz = ftell(fd);
  54.   fclose(fd);
  55.  
  56.   longsize = htonl(siz);
  57.  
  58.   printf("size = %ld", siz);
  59.  
  60.   send(n_so, (const char*)&longsize, sizeof(uint32_t), 0);
  61.  
  62.    
  63. }
Título: Re:no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: C_printfer en Enero 17, 2015, 03:48:15 pm
Puffff la verdad es que el tema sockets me parece algo lioso... He estado comparando el código que pones con algunos códigos que tengo yo pero como hay muchas funciones para transferir datos mediante sockets y no se parece a lo que tengo yo no sé dónde puede estar el error. Lo curioso es que a mí también me daba la típica violación de segmento, pero eso puede ser por mil motivos, no necesariamente debíamos tener el mismo error.

Por si te sirve, te puedo dejar el siguiente enlace para que mires alternativas: http://miweb.yabiru.com.ar/sisop/hugo/SiSop%20Related/Sockets/Sockets%20II.htm

Según recuerdo, la solución que yo encontré fue ir leyendo el archivo a enviar poco a poco e ir mandando las distintas partes, y en el destino crear un archivo y escribirlas nuevamente en el archivo creado. Si ves que no encuentras el error en tu código, podemos buscar alternativas para hacerlo.

Ya me cuentas.
S2!

PD: es que en mi opinión el tema sockets es algo más complicado que otros porque hay muchas cosillas que pueden fallar tanto en el cliente como en el servidor (creación del socket, lectura de datos en origen, envío, comunicación con el servidor...), y detectar errores llega a ser desesperante.
Título: Re:no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: stakewinner00 en Enero 17, 2015, 05:01:04 pm
Pese a que no suelo usar los sockets de linux estuve tocando un poco el cliente y el server y al final parece que el error estaba en el server, dejo el code que tengo.
Código: C
  1. #include <stdio.h>
  2.     #include <stdlib.h>
  3.     #include <errno.h>
  4.     #include <string.h>
  5.     #include <netdb.h>
  6.     #include <sys/types.h>
  7.     #include <netinet/in.h>
  8.     #include <sys/socket.h>
  9.      
  10.     int main(){
  11.      
  12.      struct sockaddr_in sv;
  13.      int so, n_so, libnd = 1;
  14.      int siz;
  15.      uint32_t longsize;
  16.      int sin_size = sizeof(struct sockaddr_in);
  17.      
  18.       so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  19.      
  20.      sv.sin_family = AF_INET;
  21.      sv.sin_addr.s_addr = INADDR_ANY;
  22.      sv.sin_port = htons(1234);
  23.      bzero(&(sv.sin_zero),8);
  24.      
  25.      if(setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &libnd, sizeof(int)) == -1){
  26.         perror("setsockopt");
  27.         exit(1);
  28.       }
  29.      
  30.      if(bind(so, (struct sockaddr*)&sv,sizeof(struct sockaddr_in)) < 0){
  31.      
  32.       printf("error bind");
  33.       exit(1);
  34.       }
  35.      
  36.      if(listen(so, 2) < 0){
  37.      
  38.        printf("error listen");
  39.        exit(1);
  40.       }
  41.      
  42.      if( ( n_so = accept(so, (struct sockaddr*)&sv, &sin_size)) < 0){
  43.      
  44.       perror("error");
  45.       exit(1);
  46.       }
  47.      
  48.      
  49.       FILE * fd = fopen("/tmp/s.c", "r");
  50.       fseek(fd, 0, SEEK_END);
  51.       siz = ftell(fd);
  52.       fclose(fd);
  53.      
  54.       longsize = htonl(siz);
  55.      
  56.       printf("size = %u", siz);
  57.      
  58.       send(n_so, (const void*)&longsize, sizeof(uint32_t), 0);
  59.       return 0;
  60.        
  61.     }

Por cierto, probe en 64 y no daba ningún segmentation fault, ya dirás si sigue dando esos errores.

Título: Re:no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: grimoire en Enero 17, 2015, 11:47:27 pm
C_printfer, Gracias por el link, estaba viendo los códigos y el de pop3 me recordó un programa que quería hacer para descargar de los mails los archivos, algo como los antiguo p2pmail, y aunque entendí la teoría de base64, nunca supe como implementarla en C para decodificar los archivos y guardar la información, pero tendré en cuenta tu pagina.

stakewinner00, Gracias por la corrección del código, me sentí torpe cuando vi que me faltaba un paréntesis en un if, pero tienes razón ya funciona.

Pues ya logré hacerlo funcionar, ya se hizo la transferencia de un pdf y un video, así que yo creo hasta ahorita todo va bien, aún no lo pruebo con computadoras distintas y no tengo linux en algún virtualizador, también se me ocurrieron ideas como usar hilos para la transferencia, intente ponerle un printf que me avisara la cantidad de bytes transferidos pero por alguna razón no me funcionó, eso mismo lo hice anteriormente en un programa para descargas de internet y sirvió pero en este nuevo fallo, pero ya será después.

Pero tengo 2 dudas:

La primera me gustaría saber si creen o si es necesario usar alguna función que regule la transferencia, me refiero a darle su tiempo a fread, fwrite, send y recv.

Por ejemplo, esperar a que fread lea una cantidad de bytes, yo lo estoy manejando mediante 1024, después esperar a que send terminé su trabajo y regresar con fread por otros 1024, de igual modo con recv y fwrite.

Algunas personas usan Waitforsingleobject en fread y fwrite, en linux todavía desconozco que se le puede asemejar pero ¿ustedes creen que sea bueno utilizar algo así para evitar errores de transferencia?

Y la segunda duda es, ¿como podría calcular los kbps de la transferencia?, estuve buscando pero solo me aparecen paginas sobre medidor de velocidad, tambien busque mediante kbps y solo encontré algo que me dio una referencia, ¿se relaciona con algún contador de tiempo?, vi algo sobre GetTickCount
Título: Re:no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: ravenheart en Enero 25, 2015, 01:25:12 pm
La primera me gustaría saber si creen o si es necesario usar alguna función que regule la transferencia, me refiero a darle su tiempo a fread, fwrite, send y recv.
Eso depende de lo que necesites. ¿Necesario? No.

Citar
Por ejemplo, esperar a que fread lea una cantidad de bytes, yo lo estoy manejando mediante 1024, después esperar a que send terminé su trabajo y regresar con fread por otros 1024, de igual modo con recv y fwrite.
Esa técnica no es buena, porque en una conexión con mucho lag la transferencia se hace eterna. El control de velocidad del envío de datos es muy complejo, pero debe ser algo más del estilo de enviar tantos bytes cada periodo de tiempo (por ejemplo, si quisieras enviar a 60 kb/s podrías enviar un paquete de 6 kb cada 100 ms).

Citar
Algunas personas usan Waitforsingleobject en fread y fwrite, en linux todavía desconozco que se le puede asemejar pero ¿ustedes creen que sea bueno utilizar algo así para evitar errores de transferencia?
Esto no es para evitar errores sino para evitar una espera activa, comprobando constantemente si hay datos.

Citar
Y la segunda duda es, ¿como podría calcular los kbps de la transferencia?,
Cuentas los kb que has enviado y los divides entre el tiempo que lleva la transferencia en curso.
Título: Re:no puedo enviar bytes leidos mediante socket, ¿como arreglo un transferencia?
Publicado por: grimoire en Enero 27, 2015, 07:08:33 pm
ok gracias, creo ya entendí la idea sobre los kbps, solo veré como implementarlo en código.  :)