Buenas a todos,
Me presento, soy un estudiante de Ingenieria Tecnica en Informatica de Gestion y estoy haciendo pequeños homebrews para DS. Concretamente estoy haciendo un cliente de descargas TFTP. En principio funciona bien, el problema es que llega un momento que el servidor manda un paquete de datos a la DS y esta se queda esperando en el 'recvfrom' y no devuelve nada. Aqui os pongo el codigo de la funcion principal:
int main() {
// Variables locales
int _PAQ_DATOS_l = 0, num_bloque = 1, _PAQ_DATOS_i = 0, sainlen;
char dato;
struct sockaddr_in sain, saout;
FILE *fichero;
// BLOQUE DE INICIALIZACION
//===========================================================================================
//FIJAR CODIGO ACK
_ACK[0] = 0;
_ACK[1] = 4;
//==============================
// Initialize PAlib
PA_Init();
PA_InitVBL();
//Inicializa el texto en la pantalla 1, fondo 0, y le da color blanco a las letras
PA_InitText(1, 0);
PA_SetTextCol(1, 31, 31, 31);
//Inicializa libreria FAT
fatInitDefault();
// Inicializa Wifi
PA_OutputText(1, 9, 10, "Iniciando Wifi");
PA_InitWifi();
PA_ConnectWifiWFC(); // Se conecta al primer punto de acceso configurado en el WFC
PA_OutputText(1, 9, 10, " ");
//Inicializacion del teclado
PA_InitKeyboard(2);
//Creaciond el socket UDP
_SOCKET = socket(AF_INET, SOCK_DGRAM, 0);
//Fijar los datos del cliente
saout.sin_family = sain.sin_family = AF_INET;
saout.sin_port = htons(69);
sain.sin_port = htons(1024);
sain.sin_addr.s_addr = INADDR_ANY;
//PedirIpUsuario();
saout.sin_addr.s_addr = inet_addr("192.168.1.101");
sainlen = sizeof (sain);
//No se lo que hace esto pero es necesario
bind(_SOCKET, (struct sockaddr *) & sain, sizeof (sain));
//=====================================================================================
PA_OutputText(1, 1, 2, "%c5IP servidor: %s", _IP_SERVIDOR);
PedirUrlUsuario();
//Creacion del fichero
fichero = fopen(_URL, "wb");
PA_OutputText(1, 1, 4, " ");
PA_OutputText(1, 1, 4, "%c5Archivo: %s", _URL);
PA_OutputText(1, 1, 5, " ");
PA_OutputText(1, 1, 7, " ");
PA_OutputText(1, 1, 6, "%c5Estado:");
//Construccion y envio del RRQ
ConstruirRRQ();
sendto(_SOCKET, _RRQ, _RRQ_i, 0, (struct sockaddr*) & saout, sizeof (saout));
PA_OutputText(1, 4, 8, "%c5Enviado RRQ");
//Recepcion del primer paquete
_PAQ_DATOS_l = recvfrom(_SOCKET, _PAQ_DATOS, DATA_SIZE, 0, (struct sockaddr*) & sain, &sainlen);
//Reestablecer el puerto de destino al generado aleatoriamente por el servidor
saout.sin_port = sain.sin_port;
while (_PAQ_DATOS_l == DATA_SIZE) {
if (ExtraerCodigoOperacion() == 5) {
GestionarError(fichero);
break;
} else if (ExtraerCodigoOperacion() != 3) {
PA_OutputText(1,1,14,"Operacion desconocida ");
do {
_PAQ_DATOS_l = recvfrom(_SOCKET, _PAQ_DATOS, DATA_SIZE, 0, (struct sockaddr *) & sain, &sainlen);
} while (ExtraerCodigoOperacion() != 3 || ExtraerCodigoOperacion() != 5);
break;
} else if (ExtraerCodigoBloque() != num_bloque && ExtraerCodigoOperacion() == 3) {
GestionarBloque(fichero, num_bloque);
break;
} else if (ExtraerCodigoBloque() == num_bloque && ExtraerCodigoOperacion() == 3) {
//Extraccion y guardado de los datos
for (_PAQ_DATOS_i = 4; _PAQ_DATOS_i <= _PAQ_DATOS_l - 1; _PAQ_DATOS_i++) {
dato = _PAQ_DATOS[_PAQ_DATOS_i];
fwrite(&dato, 1, sizeof (dato), fichero);
fflush(fichero);
}
PA_OutputText(1, 2, 8, "%c5Datos guardados ");
CrearACK(num_bloque);
sendto(_SOCKET, _ACK, _ACK_i, 0, (struct sockaddr*) & saout, sizeof (saout));
_PAQ_DATOS_l = recvfrom(_SOCKET, _PAQ_DATOS, DATA_SIZE, 0, (struct sockaddr *) & sain, &sainlen);
while (ExtraerCodigoBloque() != num_bloque + 1) { //Aun no ha llegado un paquete nuevo, la DS es mas rapida?
_PAQ_DATOS_l = recvfrom(_SOCKET, _PAQ_DATOS, DATA_SIZE, 0, (struct sockaddr *) & sain, &sainlen);
}
PA_OutputText(1, 2, 8, "%c5Recibido paquete, bloque: %d", ExtraerCodigoBloque());
num_bloque++;
if (num_bloque == 65536) num_bloque = 0;
}
}
// ULTIMO PAQUETE
//Comprobacion del codigo del bloque
if (ExtraerCodigoOperacion() == 5) {
GestionarError(fichero);
} else if (ExtraerCodigoOperacion() != 3) {
do {
_PAQ_DATOS_l = recvfrom(_SOCKET, _PAQ_DATOS, DATA_SIZE, 0, (struct sockaddr *) & sain, &sainlen);
} while (sain.sin_addr.s_addr != saout.sin_addr.s_addr);
} else if (ExtraerCodigoBloque() != num_bloque) {
GestionarBloque(fichero, num_bloque);
} else {
//Extraccion de los datos
for (_PAQ_DATOS_i = 4; _PAQ_DATOS_i <= _PAQ_DATOS_l - 1; _PAQ_DATOS_i++) {
dato = _PAQ_DATOS[_PAQ_DATOS_i];
fwrite(&dato, 1, 1, fichero);
}
//Guardar los datos
PA_OutputText(1, 4, 8, "%c5Guardando %d bytes de datos", _PAQ_DATOS_l);
fflush(fichero);
//Creacion del ACK correspondiente
CrearACK(num_bloque);
//Envio ACK
PA_OutputText(1, 2, 8, "%c5Enviado ACK para bloque %d ", num_bloque);
sendto(_SOCKET, _ACK, _ACK_i, 0, (struct sockaddr*) & saout, sizeof (saout));
PA_OutputText(1, 4, 14, "%c2FIN DE LA TRANSFERENCIA");
}
//Cierre del fd del fichero abierto
fclose(fichero);
//Fin del programa
return 0;
}
A ver si alguno de vosotros me puede hechar un cable.
Gracias de antemano.
(17/02/2010) EDIT:
El programa implementa la RFC1350 (Trivial File Transfer Protocol, con Stop & Wait), este protocolo especifica que el cliente tiene que usar un solo puerto para enviar y recibir datos, ya que el servidor los enviara al socket que le haya enviado la peticion. Lo que me pasa a mi es que el programa funciona correctamente durante un tiempo indeterminado en el que el cliente (DS) recibe los paquetes perfectamente, pero llega un momento que el servidor envia un paquete de datos y la DS se queda clavada en el "recvrfrom", pero esto puede ser en el paquete 30, en el 800 o en el 9000, es bastante aleatorio. He probado usando la funcion"select" para que espere hasta que haya una modificacion en el socket y entonces siga, y no he conseguido nada.
No creo que este comendome toda la RAM ni colapsando la CPU, por otra parte tampoco es que el servidor envie el paquete y la DS no lo lea (porque para eso es Stop & Wait).