Showing posts with label C++. Show all posts
Showing posts with label C++. Show all posts

Saturday, May 2, 2009

Aprendiendo al estilo Matrix

Por alguna extraña razón, mi lenguaje favorito es C. Por supuesto, aprecio las enormes ventajas de Java, PHP y demás, pero cuando realmente me siento en casa es cuando hago mallocs, sumo chars con enteros para conversiones, manejo cualquier tipo de dato como puntero, etc. Y aunque el mundo ha relegado a C a un segundo plano dejándolo sólo para programación de sistemas y aplicaciones en sistemas limitados, tipo microcontroladores, C no ha muerto.

Me acuerdo aún en el instituto, estudiando literatura, que había 3 tipos de vida: la vida terrenal, la vida eterna religiosa y el tercer tipo: la vida eterna gracias a la fama. Pues C tiene un nuevo tipo de vida eterna: la vida eterna gracias a la herencia (¡no hablo de objetos!).

Cualquier lenguaje "que se precie" (amantes de haskell abstenerse) hoy en día, a nivel sintactico es realmente un C un poco expandido. En los último días he tenido que hacer dos pequeños programas, uno en Java y otro en C#. En ambos era "mi primera vez" y en ambos tuve la misma sensación: con ver un ejemplo de código en internet me basta para hacer un programa sencillo que funcione. Por supuesto, llegar al "nivel maestro" con cada uno de ellos lleva años, como cualquier cosa, pero el nivel necesario para hacer un hola mundo o un bubble sort, se alcanza en cuestión de minutos, gracias a su enorme parecido con C.

Ahora tengo que hacer un proyecto para una asignatura de la carrera, y como tenía ganas de aprender python, he estado buscando cosas por google. A ser posible un cursillo/tutorial que me explique por encima todo el lenguaje sin enrollarse en cuestiones como qué es una variable, qué es un objeto y a qué hulen las nubes. Total, sabiendo C seguro que en nada lo domino ;)

Y en efecto. En el autobús volviendo a casa de la oficina y como siempre gracias a google, aprendí python. Me subí sin tener ni idea y me bajé con los conceptos claros. De aquí a Matrix sólo queda un paso.

Thursday, December 18, 2008

Lenguajes de programación

Relacionado con la entrada anterior, pero mucho más en serio, un interesante artículo sobre diversos lenguajes de programación.
Es largo, pero muy interesante. Repasa desde C hasta programación funcional. Resumen: se debería echar un vistazo a lenguajes infravalorados como LISP u Ocaml, ya que ofrecen muchas ventajas para proyectos grandes.

Thursday, December 27, 2007

¿Orientación a objetos?

Aunque digan que la medicina es una profesión vocacional, las ingenierías no se quedan atrás. No creo que nadie aguante 5 cursos (es decir, 7-8 años) de caminos, teleco o aeronáutica sólo porque "luego tienes muchas salidas". Fontanero también tiene muchas salidas, y con todo mi respeto a los fontaneros, es bastante más fácil. Y aunque la informática sea quizá el patito feo de las ingenierías, no se queda atrás. De hecho, a veces en la carrera te putean incluso un poco más, para recuperar el terreno perdido, debe de ser. El problema es que existe una cultura popular en la que si sabes escribir una carta en Word, sabes informática, si sabes navegar por Internet eres un experto y si ya sabes instalar Pequesuave Ventanas XP es que ya te falta nada para ser Guillermo Puertas.
Pero en mi caso es por puro frikismo y pasión por los chips, los bytes y todoas esas cosas. Me parecía fascinante como simplemente escribiendo una serie de comandos se podía hacer que un montón de chatarra "cobrara vida" e hiciera exactamente lo que se le decía (pantallazos azules aparte). Por aquel entonces ni siquiera tenía ordenador y me dedicaba a ojear viejos libros sobre Basic que dios sabe de dónde salieron. Más tarde cuando ya compramos el primer PC, un PIII 450Mhz el problema eran los recursos. No conocía nada de linux y en Pequesuave Ventanas para programar necesitabas "suites" de Borland o cosas similares, inalcanzables. Tras un primer intento (ridíiiiiculo) con Visual Basic (5, si no recuerdo mal) conseguí el DIV2, con el que hice mi primer matamarcianos, siguiendo un tutorial de una revista. En aquellos tiempos oscuros sin Internet la información era un tesoro y un chaval de 14 años no podía permitirse el lujo de comprar un libro de programación. En la biblioteca del pueblo sólo había un viejo libro de Pascal, que me daba la sensación de ser un lenguaje viejo e inútil. Para entonces ya había empezado a oir cosas sobre Linux y que estaba hecho en un lenguaje llamado C, al igual que muchos videojuegos, así que ese era el lenguaje a aprender. Tras mucho esfuerzo conseguí unos programas ejemplo tipo "hola mundo" en C, ¡bajados de Internet! en un ordenador del instituto y poco más tarde todo un señor libro de programación en C. Poco a poco empecé a "dominar" el tema, aunque algunas cosas me seguían pareciendo cosa de magia, y casi sigue siendo así hasta ahora (casi, ¿eh?), como pueden ser la programación Win32, DirectX, OpenGL, programación multimedia... Cuando llegué al instituto la asignatura de informática era (de nuevo, casi) mejor que el recreo. La parte de Pequesuave Oficina era para lerdos y la parte hiper-dificil de programación en C consistía en hacer un hola mundo y un programa que haga ordenaciones números enteros. Nada de quicksort: empezando por un ¿voy bien así? y alcanzando la máxima complejidad con un modo de burbuja de orden estrictamente n cuadrado y su digi-evolución, el método de burbuja mejorado, donde el bucle interno de inicia más allá de los elementos ya ordenados, que es el que viene en la wikipedia.
Y finalmente teminé le bachillerato y conseguí sustituir literatura e historia por física y programación. Tras un principio traumático con Haskell y su paradigma "no-uso-variables-pero-tengo-funciones-auxiliares-para-
guardar-información-que-necesitare-mas-tarde-y-que-
en-realidad-es-una-implemetación-tremendamente-
ineficiente-y-liosa-de-variables" pasamos a ADA, que no era tan distinto de C, aunque le añadía la funcionalidad de tipado: "no puedes sumar cantidad y 5, porque cantidad es del tipo_dinero y 5 es del tipo_integer". Pero eso era pasable, bastaba con tener un poco de cuidado y todo era coser y cantar. Hasta que en tercero llegó la programación orientada a objetos. De repente, desapareció cualquier rastro de otro tipo de programación y los profesores daban las clases rezando "padre nuestro que estás en un patrón factoría" en lugar de padre nuestro y en vez de "nos creó a su imagen y semejanza" era "heredamos de él atributos y métodos por ser una clase hija".
Y yo me preguntaba... ¿de verdad que todo lo que he aprendido hasta ahora no me vale para nada? ¿Será que los objetos es lo único que vale y que se usa y todo lo demás son tecnologías obsoletas? Yo desde luego me apaño perfectamente haciendo todas las prácticas en C sin haber aprendido a fondo ni C++ ni Java en lo que llevo de carrera. Y el núcleo de linux o GTK están hechos en C, pero quizá en C++ serían más bonitos, más fáciles y te harían café y tostadas por las mañanas... Por suerte en barrapunto me he encontrado con algunos comentarios sobre una entrevista al creador de C++ y con una simpática respuesta de Linus Torvalds que me han aclarado que la programación orientada a objetos es simplemente una forma más que tiene sus puntos fuertes y sus aplicaciones, no la panacea como nos quieren hacer ver.
Y por cierto, como dicen tambien en barrapunto, habría que ver la reacción de Linus si alguien le propone migrar el kernel de C a C++. Matarle quizá no le mate, pero seguro que contrata a esta gente para que vaya por las noches bajo su ventana ;)

Wednesday, September 12, 2007

Sockets para linux - cliente

A ver si esta vez ya me animo a ir actualizando el blog. El verano esta acabando, los exámenes están hechos, al fin tengo tiempo libre. Así que... ¿qué mejor para empezar que cumplir con lo prometido? Así que aquí va una de sockets de Berckley, por supuesto en C y en linux (GNU/Linux para los pedantes xD) La presentación... bueno, eso ya lo haré algún día.

El origen del código es una práctica para la asignatura de Sistemas Operativos Distribuidos, de la Facultad de Informática de la UPM. Pero esto es lo de menos, ya que el payload está, sólo interesa la parte de los sockets. Lo relevante es que viene de la implementación con sockets y sin estado. Esto afecta de manera que para cada comunicación se abre una nueva conexión y se cierra al terminar la petición. Algo al estilo HTTP 1.0. Bien, ¡manos a la obra!


Cuerpo del cliente
Este es el código útil que va a hacer cosas y entre ellas, enviar y recibir datos por la red. Sustituir ese código útil en los corchetes es tarea vuestra :P

RDIR *r_opendir(char *dirname) {
mensaje_t mensaje;
int s;
[...]
if ((ptr->s=conectar()) < 0) {
perror("error de conexion");
return NULL;
}
[...]
if ((aux=send(ptr->s, &mensaje, sizeof(mensaje), 0)) < 0)
perror("send mensaje");

if (recv(ptr->s, &mensaje, sizeof(mensaje), 0) < 0)
perror("recv mensaje");

close(s);
return [...];
}

Trivial, ¿verdad? Bueno, si sólo fuera eso sería estupendo, ya estaría todo claro, el código habla por sí mismo: conectar, enviar y recibir. De hecho también se podría usar read(...) y write(...) ya que s no es ni más ni menos que un descriptor de fichero. Pero se observa una sospechosa función conectar(), que como es de prever no viene en ninguna biblioteca y no hay direcciones, ni puertos ni nada de nada. Normalmente todo eso iría en el código principal, pero por hacerlo mas bonito y reusable lo separé en una función aparte, la cual no sería dificil de meter en un .h si fuera necesario.


Función conectar()
Esta es la que hace que el descriptor s contenga un socket listo para ser usado para hacer read y write sobre él, o si se prefiere, send(...) y recv(...).

int conectar(void){
struct sockaddr_in dir;
struct hostent *host_info;
int s;

if (getenv("SERVIDOR") == NULL || getenv("PUERTO") == NULL){
printf("Establecer SERVIDOR y PUERTO en variables de entrono\n");
return -1;
}

if ((s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("error creando socket");
return -1;
}
host_info=gethostbyname(getenv("SERVIDOR"));
memcpy(&dir.sin_addr.s_addr, host_info->h_addr, host_info->h_length);
dir.sin_port=htons(atoi(getenv("PUERTO")));
dir.sin_family=PF_INET;
if (connect(s, (struct sockaddr *)&dir, sizeof(dir)) < 0) {
perror("error en connect");
close(s);
return -1;
}
return s;
}

Lo primero se definen dos estructuras de datos para contener la informacion del socket a crear y del host destino.
En segundo lugar se comprueba (de manera chapucera) que las variables de entorno que indiquen el server y puerto están puestas. Se podrían usar valores fijos, pedirlos interactivamente, o lo que prefiramos.
Más tarde se crea el socket en sí, con una función sorprendentemente llamada socket(...). Lo creamos del tipo stream y protocolo TCP (sí, un poco de redundancia nunca viene mal, jeje...). Una vez tenemos el socket creado, necesitamos conectarlo y para ello necesitamos una direccion. Como lo que tenemos es un nombre (host.dominio.com) lo resolvemos con gethostbyname(...) y vamos construyendo la estructura que nos define el host destino. El siguiente campo se rellena con el puerto destino, que se ha de pasar a formato de red con htons(...) (por el tema de máquinas big-endian/little-endian). De hecho este nombre tan raro viene de "host to network, short"
Llegados a este punto tenemos el socket creado y una estructura que nos define exactamente dónde conectarlo. Pues una llamada a connect(...) y tenemos un socket listo para usar.

Resumen
El proceso en caso de no haber conexión, en el cliente es:
crear socket -> identificar host+puerto destino -> conectar socket -> enviar/recibir -> cerrar socket.

El caso del servidor lo dejamos para la siguiente entrada.