|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: EOF |
| 4 | +author: Federico Manuel Gomez Peter |
| 5 | +date: 05/05/2021 |
| 6 | +tags: [correccion, Files] |
| 7 | +snippets: none |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +Observar el siguiente ejemplo y reflexionar: ¿qué problema tiene? |
| 12 | + |
| 13 | +```c |
| 14 | +int main(int argc, const char *argv[]) { |
| 15 | + socket_t skt; |
| 16 | + socket_init(&skt); |
| 17 | + socket_connect(&skt, argv[1], argv[2]); |
| 18 | + // do something |
| 19 | + socket_uninit(&skt); |
| 20 | +} |
| 21 | +``` |
| 22 | +
|
| 23 | +Como futuros profesionales, debemos contemplar que nuestros programas no siempre van a ir |
| 24 | +por el camino feliz de la ejecución. Algo puede _malir sal_ y tenemos la responsabilidad |
| 25 | +de que nuestros programas sean lo suficientemente robustos ante fallas inesperadas. |
| 26 | +¿Qué pasa si el usuario, al ejecutar el programa, no le pasa ningún argumento? |
| 27 | +¿Qué pasaría si el sistema operativo no pudo darme un _file descriptor_? |
| 28 | +¿Qué pasaría si no logro conectarme a un servidor, y después quiero hacer |
| 29 | +un `socket_send`? Nuestros programas pueden fallar, y debemos chequear que esto no suceda, |
| 30 | +y si sucede, abortar la ejecución de forma ordenada, liberando **todos** los recursos solicitados. |
| 31 | +
|
| 32 | +```c |
| 33 | +#define ARGV_HOSTNAME_INDEX 1 |
| 34 | +#define ARGV_SERVICE_INDEX 2 |
| 35 | +#define ARGV_FILEPATH_INDEX 3 |
| 36 | +#define ARGC_MANDATORY_QUANTITY 4 |
| 37 | +
|
| 38 | +int main(int argc, const char *argv[]) { |
| 39 | + if (argc != ARGC_MANDATORY_QUANTITY) { |
| 40 | + fprintf(stderr, "Uso: %s <hostname> <servicio> <path al archivo>\n", argv[0]); |
| 41 | + return -1; |
| 42 | + } |
| 43 | +
|
| 44 | + socket_t skt; |
| 45 | + FILE *file; |
| 46 | + if (socket_init(&skt) < 0) { |
| 47 | + // Como no alloqué nada antes de esta función, no hago nada |
| 48 | + // (Se asume que lo que alloque la función socket_init fue liberado si |
| 49 | + // tuvo alguna falla interna) |
| 50 | + fprintf(stderr, "Falló socket_init (%s)\n", strerror(errno)); |
| 51 | + return -1; |
| 52 | + } |
| 53 | +
|
| 54 | + if ( (file = fopen(argv[ARGV_FILEPATH_INDEX], "r")) == NULL) { |
| 55 | + fprintf(stderr, "No pude abrir el archivo (%s)\n", strerror(errno)); |
| 56 | + socket_uninit(&skt); |
| 57 | + return -1; |
| 58 | + } |
| 59 | +
|
| 60 | + if (socket_connect(&skt, argv[ARGV_HOSTNAME_INDEX], argv[ARGV_SERVICE_INDEX]) < 0) { |
| 61 | + fprintf(stderr, "No pude conectarme (%s)\n", strerror(errno)); |
| 62 | + fclose(file); |
| 63 | + socket_uninit(&skt); |
| 64 | + return -1; |
| 65 | + } |
| 66 | +
|
| 67 | + // do something |
| 68 | + |
| 69 | + fclose(file); |
| 70 | + socket_uninit(&skt); |
| 71 | + return 0; |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | + |
| 76 | +Cualquiera de estas funciones pueden fallar, y si lo hacen, nos imposibilitaría a continuar la ejecución. |
| 77 | +Por esta razon, se chequean errores y se liberan los recursos de forma ordenada. La contra es que |
| 78 | +el código se hace mas ilegible. En clases posteriores vamos a ver cómo en C++ podemos tener la misma robustez |
| 79 | +que este programa, conservando la legibilidad del primer programa. Mientras tanto, en C nos tenemos que conformar |
| 80 | +con esto (en C existen otros métodos para mejorar la legibilidad, pero requieren el uso del infame `goto` y |
| 81 | +en la facultad eso es palabra prohibida). |
0 commit comments