[Tip] Simple serializador para C

Simple Net Serializer

Simple Net Serializer

El otro día necesitaba serializar unos mensajes para una aplicación cliente/servidor que estaba desarrollando.

En un primer momento intenté buscar alguna librería que me diera lo que estaba buscando. Probé con GLib pero no tiene nada para serializar mensajes (se pueden serializar objectos con GObject).

Decidí hacer una implementación sencilla de lo que tenia mente.

Así fue como desarrolle el siguiente código:

// PUSH/POP Simple net serializer

#define PUSH_BEGIN(buff,l)       { int i = 0; int lm = (l); char* b = (char*) (buff);
#define PUSH_BYTE(b)                 assert(i+1 <= lm); b[i++] = (b);
#define PUSH_SHORT(s)                assert(i+sizeof(short) <= lm); { short* ps = (short*) &b[i]; *ps = htons((s)); i += sizeof(short); }
#define PUSH_INT(s)                  assert(i+sizeof(int) <= lm); { int* ps = (int*) &b[i]; *ps = htonl((s)); i += sizeof(int);}
#define PUSH_SZ(s)                  { int l = strlen(s); assert(i+l+sizeof(int) <= lm); PUSH_INT(l); memcpy(&b[i],s,l); i += l; }
#define PUSH_END(l)              (l) = i; }

#define POP_BEGIN(buff,l)        { int i = 0; int lm = (l); char* b = (char*) (buff);
#define POP_BYTE(b)              assert(i < lm); (b) = b[i]; i++;
#define POP_SHORT(s)             assert(i+sizeof(short) <= lm); (s) = ntohs(  *((short*) &b[i])     ); i += sizeof(short);
#define POP_INT(s)               assert(i+sizeof(int) <= lm); (s) = ntohl(  *((int*) &b[i])     ); i += sizeof(int); printf("val: %i\n",(s));
#define POP_SZ(s)                { int l = 0; POP_INT(l);  assert(i+l <= lm); (s) = (char*) malloc(l+1); memcpy(s,&b[i],l); s[l] = '\0'; i += l; }
#define POP_END()             }

A poco que examinéis el código comprobareis que se trata en realidad de una macro.

Esta implementación cumple mis requisitos:

  • Eficiente. Las macros se resuelven en el código y es equivalente a las funciones inline.
  • Sencillo. La nomenclatura de las macros auto-describe su propósito, PUSH_x para agregar y POP_x para extraer.
  • Poca sobrecarga. La mayoría de los serializadores incluyen el tipo de dato del dato agregado. En este caso el tipo está bien determinado e identifica unívocamente el tipo de mensaje.
  • Depuración. Gracias a los assert() puede comprobar que el tamaño de los bufferes para el envio/recepción de los mensajes es correcto durante la fase de pruebas.
  • Portable. El uso de ntoh/hton posibilita la independencia de arquitectura big/little endian.

Así por ejemplo si queremos mandar el siguiente mensaje: “bote de champú”,3,”suave”, éste seria el código resultante:


#define MAXBUFFER 1024

char buff[1024];
int len;

PUSH_BEGIN(buff,MAXBUFFER)
PUSH_SZ("bote de champu")
PUSH_INT(3)
PUSH_SZ("suave")
len= PUSH_END()

Seguro que no es la mejor implementación y es probable que tenga algun bug. Si ves algo que no te gusta o bugs, te animo a que lo modifiques y comentes. Libero el código bajo licencia BSD.

Translate to:English
MenefanteMenéame TwitterTwitter

[Tip] Hoard, gestor de memoria dinámica multiprocesador

Hoard, gestor de memoria dinámica

Hoard, gestor de memoria dinámica

Si alguna vez habéis programado en C/C++, casi seguro que habréis tenido que reservar y liberar memoria con malloc/free o new/delete.

Estas operaciones internamente gestionan la memoria de proceso asignando slices de memoria libre.  Esta gestión tiene un coste u overhead de procesamiento. Si nuestro programa es multihebrado este procesamiento se vuelve más complejo.

Emery Berger, profesor de la Universidad de Massachusetts, se dio cuenta que la implementación de malloc()/free() de la stdlib, se podía mejorar y empezó a trabajar en Hoard.

Hoard ha sido comparado con otros gestores de memoria y ha salido victorioso en varios tests. Estos screenshots arrojan los detalles.

Esta disponible para GNU/Linux, Windows y Solaris bajo licencia GPL.

La gran ventaja de usar Hoard, es que no es necesario recompilar un programa (salvo que sea estático) para aprovechar sus bondades, ya que usa la misma sintaxis que las funciones originales de stdlib.

Para usarlo en GNU/Linux basta con indicar a LD, que precargue la libreria de Hoard:

export LD_PRELOAD=/ruta-a-libreria/libhoard.so

Ahora sólo tenemos que ejecutar nuestro programa con esta variable de contexto.

Es un buen gestor de memoria para aquellos desarrollos de servidores multithreads.

Translate to:English
MenefanteMenéame TwitterTwitter

GoLang, nuevo modelo de programación

GoLang logo

GoLang logo

Translate to:English

Estos días he estado mirando la sintaxis (y semántica) de programación de GoLang.

Desarrollo siempre que puedo en C. Pero recurro a Python cuando tengo que hacer alguna GUI (PyQt4) o desarrollo web (Django).

Con GoLang se abre (a priori) una opción que llevaba tiempo buscando: “código nativo con la flexibilidad de Python“.

Mis objetivos se verán cumplidos si la relación tiempo de ejecución/tiempo de desarrollo sale más favorable que respecto a Python. El tiempo lo dirá.

Ahora mismo necesito cambiar el chip para este nuevo lenguaje.

Voy a resumir (desde mi punto de vista, claro) las principales claves del nuevo modelo de programación que GoLang presenta:

  • Inicialización de las variables: ¿cuántas veces no habeis tenido un segmentation fault por variables no inicializadas? Es sin duda una característica que echaba de menos.
  • Switch de cualquier tipo: poder hacer switch sobre strings es una característica muy necesitada por mi, tuve que recurrir a macros para poder emularla.
  • Defer: esta nueva keyword es muy interesante. En la mayoría de funciones relacionadas con I/O, es posible que no se cumpla una condición y por ejemplo tengamos que cerrar un archivo y salir. Si la cóndición se cumple, al final de la operación es necesario cerrar dicho archivo. Actualmente yo usaba un if para comprobar la condición a falso, cerrar el fichero en el cuerpo del if, y retornar. En casos más complidados usaba el peligroso goto. Pues bien, con “defer fclose(fd)” justo despúes del fopen(), conseguimos que justo antes de retornar la función, se cierre el fichero. Es decir, defer, encola llamadas a función en una cola LIFO a ejecutar una vez terminada la ejecución de la función. Creo que esto es muy útil y genera un código muy limpio.
  • Campos vectoriales o funciones con retorno múltiple: desde el punto de vista algebraico, las funciones de C son campos escalares, y = f(x1,x2,…,xn), en GoLang podemos devolver más de un valor. Ésto es tremendamente útil y ayuda que los programas sean más limpos. Hasta ahora lo habitual era devolver un código de retorno (Success o el nº de error) y pasar el puntero de la variable a devolver. Ej: En C, int getData(FILE* fd, char** data,int* len), con GoLang:  func getData(fd *FILE) (data *char,len int)
  • (Casi) Adiós al “;”: con GoLang no es necesario el uso del “;” en los bloques top level. La verdad es que no acabo de entender muy bien donde es necesario o no. En los códigos de ejemplo he encontrado sitios donde hay “;” y no es necesario. Eliminándolo el programa sigue compilando. Creo que se colará más de un “;” innecesario.
  • Literales ideales: las constantes y demás literales tienen un tamaño de ¡1024 bits! Podemos tener el número Pi con una gran precisión. Luego su manejo dependerá del tipo de variable donde lo almacenemos.
  • El tipo “map” (diccionario): el diccionario es unos de mis tipos preferidos en Python. Ahora lo puedo usar en GoLang :).
  • Los threads con Go: adiós al uso de la libreria pthread para crear hilos. Crear un hilo en GoLang es tan sencillo como ” go <funcion>”. Simplemente impresionante.
  • Sincronización y comunicación con CSP: Según mi profesor de programación concurrente, Dijkstra sólo consideraba como sincronización segura de threads la que estaba hecha mediante canales. GoLang implementa la semántica de programación CSP por canales. Esta característica dará mucho que hablar (y escribir).
  • Declaración implicita: ya no es necesario declarar la variable. Con “:=” creamos una variable con el tipo más acertado para el literal que usamos. Ej; ” i := 1″.
  • Test unitarios: los test de unidad son un latazo. GoLang incorpora en su framework soporte para realizar estos test. Sin duda ganaremos tiempo para otras cosas.

Creo que estas son las principales características de GoLang que harán cambiar la forma de programar a más de uno.

Por último os quiero comentar unos detalles sobre GoLang que me llaman la atención.

  • Ahora mismo hay soporte para i586, amd64 y ARM. ¿Por qué ARM? Creo que Google pretende recompilar las aplicaciones o el propio Android con GoLang.
  • ¿Qué pasa con Windows? Ahora mismo no podemos crear código que corra en Windows. Los desarrolladores de GoLang dicen que por ahora no va a ver soporte para Windows. Creo que soportar o no Windows será decisivo en el futuro de este nuevo lenguaje.

Bueno, ahora toca empezar a programar con GoLang 🙂

Entradas relacionadas:

GoLang no es para Windows
Benchmark a GoLang: servidor web en Go vs Python

Translate to:English
MenefanteMenéame TwitterTwitter

El lenguaje de Google ya existía

Google Go Language

Google Go Language

Madre mía. Acaba de nacer (públicamente) y ya esta generando bastante revuelo. Resulta que Google está desarrollando su propio lenguaje de programación bajo el nombre:  Go. Entre las bondades del lenguaje destaca que tiene la potencia de Python (el lenguaje preferido por Google) , pero el código es compilado como en C y soporta pasos de mensajes CSP para sincronización y comunicación de threads. En dos palabras, promete mucho.

El caso es que en su  issue tracker ha aparecido un tal “fmccabe” comentando que el ya tiene un lenguaje bajo ese nombre desde hace 10 años (incluso tiene un libro). El tema está caliente y ya lleva unos 49 comentarios de usuarios aportando nombres alternativos.

Os pongo algunas propuestas:

  • Golang (como Erlang de Ericsson): Creo que es el más apropiado ya que coincide con el dominio del proyecto (golang.org).
  • Goto
  • GCP (Google C Python)
  • Go2 (Google Go)
  • GG (Google Go)

Esperemos que el nombre sea lo de menos y que el lenguaje resultante sea potente y bueno para el desarrollo de SaaS.

P.D: Ahora mismo la compilación de Go (codename) tiene muchos problemas. No me va 😦

¿qué nombre es más acertado? ¿alguno más?

Actualización:  Paper sobre el lenguaje Go! (anterior al de Google)
Translate to:English
MenefanteMenéame TwitterTwitter