UTNianos

Versión completa: [Sistemas Operativos] Sockets y Sendfile
Actualmente estas viendo una versión simplificada de nuestro contenido. Ver la versión completa con el formato correcto.
Páginas: 1 2
Hola, estoy haciendo unos programas de pruebas para acostumbrarme al tema para poder encarar bien el tp de este cuatrimestre, y lo unico que me falta es poder pasar archivos. Lei que para enviar archivos puedo usar la funcion sendfile, pero no la termino de entender, ni del man y de internet :( alguien podria contarme algo acerca de esta funcion? y otra cosa, en el lado del cliente, donde tendria que poner recv su mandara un send normal, que tengo que poner? existe un recvfile o algo? Gracias!!!!
si los archivos son de texto podes leerlos en "buffers" (vectores de string) e ir mandandolos asi... si son binarios podes hacer algo parecido a eso, pero con una estructura que en este momento no recuerdo...

nosotros en un tp que hicimos hace un tiempo pusimos eso y nos anduvo muy bien!

saludos!
con un while recorre el archivo, y levanta los bytes en un buffer de algun tamaño (1K, por ejemplo) y lo vas mandando con send().
Yo me siento re perdido con esta materia, si alguien tiene algun apunte gordo y salvavidas de sockets se lo voy a agradecer eternamente!!!
http://beej.us/guide/bgnet/
Supongo que ya lo deben tener como referencia en el TP, pero es de lo mejorcito para empezar con el tema de sockets.

SIno, algo mas pesadito, tenes la serie de libros de Richard Stevens (deben andar por la mula o torrents, seguro)
http://www.kohala.com/start/#books
Cita:con un while recorre el archivo, y levanta los bytes en un buffer de algun tamaño (1K, por ejemplo) y lo vas mandando con send().

Yo tenia pensado hacer un header con el tamaño del paquete que envio.
¿Esta bien?

Tengo ganas de hacer eso, porque tengo la siguiente duda:
Si voy enviendo la info en paquetes de 1K, y me envian un archivo de 1030 bytes por ejemplo, va a haber un paquete que tenga solo 6 bytes, por lo que la duda es ¿¿¿Como me doy cuenta que tiene menos de 1K??? Ya que, si escribo el archivo bit a bit, voy a terminar almacenando basura al final del archivo.
Teseracto escribió:
Cita:con un while recorre el archivo, y levanta los bytes en un buffer de algun tamaño (1K, por ejemplo) y lo vas mandando con send().

Yo tenia pensado hacer un header con el tamaño del paquete que envio.
¿Esta bien?

Tengo ganas de hacer eso, porque tengo la siguiente duda:
Si voy enviendo la info en paquetes de 1K, y me envian un archivo de 1030 bytes por ejemplo, va a haber un paquete que tenga solo 6 bytes, por lo que la duda es ¿¿¿Como me doy cuenta que tiene menos de 1K??? Ya que, si escribo el archivo bit a bit, voy a terminar almacenando basura al final del archivo.

hay unas funciones que te dicen el tamaño final del archivo (en bytes)
entonces vos envias en bloques de 1024K con un while
algo tipo:

while (loQueQueda < 1024)
{
send(bloque, 1024);
funcionQueLeeOtroBloque();
}
send(bloque, loQueQueda);


Igual, te recomiendo que uses un header (una pequeña estructura que tiene un codigo de mensaje tipo "0x00" = "mensaje de tal cosa", "0x01" = "lo que viene es un pedazo del archivo" y cosas asi...
Posta, lo de sockets es un tema jodido, pero se puede aprender... requiere de MUCHA MUCHA practica y prestenle atencion a hacer las cosas BIEN. Una cosa que anda, pero esta programada de una forma "fea" va a traer errores jodidisimos de resolverrrrrrrrr.

saludos!
Aca encontre la funcion que use en TP. Recibe como parametro un puntero al archivo y el FileDescriptor del socket por el que se va a mandar. Fijate si te sirve.


int EnviarArchivo(FILE *xArch, int xSckFD) {
/* Bytes Leidos del Archivo */
int bytesleidos = 0;
/* Buffer de Datos para enviar al Socket */
char strDatos[4096];

memset (strDatos, '\0', 4096);

while(bytesleidos = fread(strDatos, 1, 4096, xArch)) {
if ((EnviarDatos(xSckFD, strDatos, &bytesleidos)) == -1) {
return(-1);
}
memset (strDatos, '\0', 4096);
}

/*free(strDatos);*/
fclose(xArch);
close (xSckFD);

return(1);
}

int EnviarDatos(int xSckFD, char *xBuf, int *xLen) {

int total = 0; /* Bytes Enviados */
int bytesleft = *xLen; /* Bytes Pendientes por mandar */
int n; /* Bytes que mando realmente */

while(total < *xLen) {
n = send(xSckFD, xBuf+total, bytesleft, 0);
if (n == -1) break;
total += n;
bytesleft -= n;
}

*xLen = total; /* Devuelve la cantidad enviada */

if (n == -1) return(-1);
return(1);
}



Gracias por el cachito de codigo!!! estoy seguro que nos sera mas que util!! muchas Gracias!
ebric escribió:http://beej.us/guide/bgnet/
Supongo que ya lo deben tener como referencia en el TP, pero es de lo mejorcito para empezar con el tema de sockets.

Nosotros arrancamos con esta guía allá por el 2005, y nos fue muy bien.


Off-topic:
¿Cómo son los TPs ahora? ¿Qué tienen que hacer? Yo tengo 5 TPs aprobados de los viejos, por ahí les sirven.
Cita:Igual, te recomiendo que uses un header (una pequeña estructura que tiene un codigo de mensaje tipo "0x00" = "mensaje de tal cosa", "0x01" = "lo que viene es un pedazo del archivo" y cosas asi...

Es lo primero que se me ocurrio. Pero encontramos una idea mas copada, que es enviarle al principio la info en bytes con el tamaño del archivo a enviar, y despues enviar otros paquetes con el archivo, tal como hace al protoclo HTTP al enviar un HTTP 200 junto con el tipo de archivo primero.


Off-topic:
Cita:¿Cómo son los TPs ahora? ¿Qué tienen que hacer? Yo tengo 5 TPs aprobados de los viejos, por ahí les sirven.

Desde este cuatri, hay que hacer programitas cliente en Windows (utilizando winsock.h y algunas librerias supeustamente standard de C para multithreading)y servidores en linux :P.
Y el cliente recibe hasta??? como se da cuenta cuando termino de recibir el paquete entero para "grabar el archivo" ? :P

es muy flashero este tp... igual a mi particularmente lo q mas me rompe las pelotas, es no poder utilizar manejos de memoria con las librerias standard de C y tener q usar las de windows, q hacen lo mismo pero con nombres mas largos y molestos en mayusculas... jajajaja
ebric escribió:Aca encontre la funcion que use en TP. Recibe como parametro un puntero al archivo y el FileDescriptor del socket por el que se va a mandar. Fijate si te sirve.


int EnviarArchivo(FILE *xArch, int xSckFD) {
/* Bytes Leidos del Archivo */
int bytesleidos = 0;
/* Buffer de Datos para enviar al Socket */
char strDatos[4096];

memset (strDatos, '\0', 4096);

while(bytesleidos = fread(strDatos, 1, 4096, xArch)) {
if ((EnviarDatos(xSckFD, strDatos, &bytesleidos)) == -1) {
return(-1);
}
memset (strDatos, '\0', 4096);
}

/*free(strDatos);*/
fclose(xArch);
close (xSckFD);

return(1);
}

int EnviarDatos(int xSckFD, char *xBuf, int *xLen) {

int total = 0; /* Bytes Enviados */
int bytesleft = *xLen; /* Bytes Pendientes por mandar */
int n; /* Bytes que mando realmente */

while(total < *xLen) {
n = send(xSckFD, xBuf+total, bytesleft, 0);
if (n == -1) break;
total += n;
bytesleft -= n;
}

*xLen = total; /* Devuelve la cantidad enviada */

if (n == -1) return(-1);
return(1);
}





Ebric te hago una preguntita.. tenes una funcion "recibir_archivo" ? para el cliente en win??? yo hize una y me gustaria comparar para ver q onda para saber cuando "termino de descargar" porque como yo lo hize, esto termina cuando recibe un paquete vacio y no me convence.

Muchas gracias!!
Aca te paso la funcion. Esta hecha con las SysCalls de Linux, porque cuando hice el TP no te pedian clientes Windows =P

Ignora el printf ("CelListoParaRecibirACel\n");, quedo de algun debugueo, jajaja!.



/* Funcion que se encarga de Recibir Datos por el Socket y los graba en un Archivo (Binario) */

int RecibirArchivo(FILE *xArch, int xSckFD, int xSckArch, char *ip) {
/* Bytes Leidos por el Socket */
int nbytes = 0;
/* Buffer de Datos para escribir en el Archivo */
char strDatos[4096];

Header *stHeaderSend;

stHeaderSend = malloc (sizeof (Header));

memset (strDatos, '\0', 4096);

/* Avisarle q ya esta listo */
CrearHeader(stHeaderSend, listoParaRecibir, 0, ip);

if (EnviarMsg (xSckFD, (char *) stHeaderSend, sizeof(*stHeaderSend)));
else return -1;

printf ("CelListoParaRecibirACel\n");

while(1) {

if ((nbytes = recv(xSckArch, strDatos, 4096, 0)) <= 0) {

if (nbytes == 0) break;

fclose(xArch);
return(-1);
}
else {

strDatos[nbytes] = '\0';
fwrite(strDatos, 1, nbytes, xArch);
}
memset (strDatos, '\0', 4096);
}

/* free(strDatos); */

fclose(xArch);

/* close (xSckArch); */

return(1);
}



Muchisimas gracias!!!
Páginas: 1 2
URLs de referencia