Simple Network Library
De Wikipedia, la enciclopedia libre
| Simple network library | |
|---|---|
| Desarrollador | Jesús Hernández Gormaz (autor inicial) |
| Última versión estable | 0.0.1 (9 de Junio del 2009) |
| Última versión en pruebas | 0.0.0 (5 de Abril del 2009) |
| Escrito en | C |
| S.O. | Multiplataforma |
| Género | Biblioteca informática |
| Licencia | GPL (software libre) |
| En español | Sí |
| Sitio web | www.snl.ya.st |
Simple Network Library (SNL) es una biblioteca informatica desarrollada con el lenguaje C que proporcionan funciones para realizar operaciones de comunicación en red, la primera version de esta biblioteca fue acabada el 5 de abril de 2009.
Proporciona herramientas para el desarrollo de videojuegos y cualquier otra aplicación. Una de sus grandes virtudes es el tratarse de una biblioteca multiplataforma, soportando oficialmente los sistemas GNU/Linux y OpenSolaris, además de otras arquitecturas/sistemas como windows, MacOS, etc. Las siglas le vienen de Simple Network Library que se traduce como biblioteca de red simple. Desarrollada inicialmente por Jesús Hernández Gormaz, desarrollador de videojuegos para la plataforma GNU/Linux entre otros programas informáticos programados.
Soporta los protocolos de IP tanto de IPv4 como de IPv6 además de los protocolos de comunicación TCP y UDP.
La biblioteca se distribuye bajo la licencia GPL.
[editar] Ejemplos
Ejemplo del uso de SNL para programar un cliente HTTP usando TCP sobre IPv4 en C.
/* testSNL Copyright (C) 2009 Jesús Hernández Gormaz Fecha de creacion: 5 de abril del 2009 (Siglo XXI) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Este programa es software libre. Puede redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General de GNU según es publicada por la Free Software Foundation, bien de la versión 3 de dicha Licencia o bien (según su elección) de cualquier versión posterior. Este programa se distribuye con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA, incluso sin la garantía MERCANTIL implícita o sin garantizar la CONVENIENCIA PARA UN PROPÓSITO PARTICULAR. Para más detalles, véase la Licencia Pública General de GNU. Debería haber recibido una copia de la Licencia Pública General junto con este programa. En caso contrario, escriba a la Free Software Foundation, Inc., en 675 Mass Ave, Cambridge, MA 02139, EEUU. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <SNL/SNL.h> int main(int argc, char *argv[]){ if(argc < 2){ printf("Para usar este ejemplo de SNL debe de indicar un dominio"); printf(" despues del comando con el que ejecuta el programa, por"); printf(" ejemplo:\n %s www.fsf.org\n", argv[0]); exit(-1); }else{ /*la variable conexión guardara el identificador de la conexión el cual deberemos de pasarlo a las funciones cuando enviemos orecivamos datos, etc, etc, etc.*/ int conexion; /*texto es el array que usaremos como buffer para enviar y recibir datos, con medio kilobyte es suficiente ya que normalmente las paginas pesan unos pocos kilobytes (sin contar las imagenes) y asi nuestro ejemplo leera varias veces el socket para poder recibir toda la pagina*/ char texto[512]; /*las dos variables siguientes son respectivamente para guardar la direccion del host, la IP, y para guardar un texto con la informacion de SNL*/ char direccion[512], informacion[501]; /*para trabajar con la conexión usaremos un grupo de conexiones por ser mejor que trabajar con la conexión directamente incluso cuando solo necesitamos una conexión, el grupo nos permite comprobar si hay datos esperando que los leamos en algun socket sin que la aplicación se quede a la espera de que haya datos en el socket*/ grupo_conexiones *a; /*mostramos en terminal un texto que indica que el programa esta ejecutandose y que vamos a empezar con la conexion*/ printf("\nEjecucion\n"); /*empezamos a llenar texto con la peticion HTTP que enviaremos despues*/ strcpy(&texto[0], "GET "); /*mostramos en pantalla el host al que nos conectaremos*/ printf("Host: %s\n", argv[1]); /*usamos la funcion de DNS para IPv6 de forma que si se obtiene una direccion parecida a 1F::F0:AB es que la maquina en la que ejecutamos este ejemplo ya funciona con IPv6, pero este ejemplo es de IPv4, por lo que esta es la unica funcion de Ipv6 que usaremos en este ejemplo por ser la que más difiere de su equivalente para IPv4, el primer argumento es la cadena donde queremos guardar la direccion IP, el segundo el host, el tercero es el servicio pero lo dejamos como null ya que no necesitamos conocer el puerto del servicio ni el servicio de un puerto en este ejemplo además de no haber modificado los ficheros de configuracion del sistema para configurar este ejemplo como un servicio (esto limita los puertos que podemos usar), el cuarto la longitud maxima de la cadena de caracteres de la direccion (igual que antes al obtener el texto de la informacion de SNL) y el ultimo es la longitud del servicio, 0 como le pasamos NULL*/ SNL_DNS(&direccion[0], argv[1], NULL, 1023, 0); /*imprimimos en la terminal el host y la Ipv6 obtenida*/ printf("DNS IPv6 obtenido para %s: %s\n", argv[1], &direccion[0]); /*usamos la funcion de DNS para IPv4, el primer argumento es donde se copiara la direccion IPv4 y el segundo el host*/ SNL_DNS_IPv4(&direccion[0], argv[1]); /*igual que antes, mostramos el host y la IPv4 en pantalla*/ printf("DNS IPv4 obtenido para%s: %s\n", argv[1], &direccion[0]); /*continuamos rellenando el buffer con la peticion GET de HTTP que enviaremos*/ strcat(&texto[0], "http://"); strcat(&texto[0], argv[1]); strcat(&texto[0], "/"); strcat(&texto[0], " HTTP/1.1\n\rHost: "); strcat(&texto[0], argv[1]); strcat(&texto[0], "\n\rAccept: text/html\n\rKeep-Alive: 300\n\rProxy-Connection: keep-alive\n\r\n\r"); /*iniciamos una conexión de TCP sobre IPv4 en la direccion IP que obtuvimos antes en el puerto 80, el puerto usado para el protocolo HTTP*/ conexion= SNL_conectar_TCP_IPv4(&direccion[0], 80); /*comprobamos si conseguimos conectarnos*/ if(conexion == SIN_CONEXION){ printf("problemas conectando\n"); exit(-1); } printf("conectado\n"); /*creamos un nuevo grupo de conexiones indicando como conexión de escucha SIN_CONEXION ya que en este ejemplo no aceptaremos conexiones como si fuese un servidor*/ a= SNL_nuevo_grupo_conexiones(SIN_CONEXION); /*añadimos la conexión abierta al grupo*/ SNL_nueva_conexion_grupo(conexion, a); /*enviamos el buffer que preparamos con la peticion HTTP y comprobamos que todo el buffer se enviara*/ if(SNL_enviar_grupo_TCP(a, &texto[0], strlen(&texto[0]), 0) == 0){ printf("enviado:\n\n"); printf("%s\n\n", &texto[0]); }else{ exit(-1); } /*cambiamos el tiempo de espera del grupo a que suceda algo en los sockets*/ SNL_tiempo_espera_grupo(a, 2, 0); /*esta funcion se encargara de comprobar todas las conexiones del grupo menos la conexión de escucha*/ SNL_comprobar_grupo_conexiones(a); /*volvemos a cambiar el tiempo de espera del grupo para dar mas tiempo al servidor para enviar la respuesta*/ SNL_tiempo_espera_grupo(a, 5, 500000); /*imprimimos texto en la terminal*/ printf("Esperando respuesta del servidor:\n\n"); /*iniciamos un bucle while en el que la condicion es que la conexión en la que ha sucedido algo del grupo sea la conexión que iniciamos antes (esto siempre se cumplira ya que es la unica del grupo, a no ser que no haya ninguna y el retorno sea SIN_CONEXION*/ while(SNL_conexion_activa_grupo_conexiones(a) == conexion){ /*intentamos leer datos recividos en el socket y comprobamos si da error al leer datos recividos lo cual puede ser por que el servidor cerrase la conexión si devuelve 0 o por error en la recepcion de los datos o error en la conexión si es -1*/ if(SNL_recibir_TCP(conexion, &texto[0], 512, 0) <= 0){ printf("\n\nproblemas reciviendo datos del servidor,"); printf(" puede que el servidor hubiese cerrado la conexion"); /*salimos del bucle*/ break; }else{ /*como conseguimos recibir datos los mostramos en la terminal*/ printf("%s", &texto[0]); } /*comprobamos si no hay ninguna conexión que este aun activa*/ if(SNL_comprobar_grupo_conexiones(a) == -1){ /*salimos del bucle*/ break; } } printf("\n\nsi no se muestran datos recibidos desde el servidor puede ser"); printf(" que el tiempo de espera se excedio del esperado"); /*cerramos todas las conexiones del grupo y eliminamos el grupo liberando la memoria ocupada por este*/ SNL_cerrar_grupo_conexiones(a); printf("\n\ndesconectado\n"); /*copiamos a informacion el texto con la informacion de SNL y el 500 indica que el array puede guardar como maximo una cadena de 500 caracteres, sin contar el carácter nulo de fin de cadena de caracteres*/ informacion_biblioteca_SNL(&informacion[0], 500); /*mostramos la informacion de SNL obtenida al principio*/ printf("\n%s\n\n", &informacion[0]); printf("El texto anterior cifrado:\n"); /*encriptamos el texto usando la funcion de cifrado de bits iguales que tiene SNL, esto es solo para mostrar un ejemplo de esta funcion*/ EncriptarTexto_CifradoBitsIguales(&informacion[0], "Free software as in freedom"); printf("\n%s\n\n", &informacion[0]); printf("Fin\n"); } exit(0); }
Ejemplo del uso de SNL para programar un sencillo servidor usando TCP sobre IPv4 en C.
/* chatserverSNL Copyright (C) 2009 Jesús Hernández Gormaz Fecha de creacion: 8 de Junio del 2009 (Siglo XXI) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Este programa es software libre. Puede redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General de GNU según es publicada por la Free Software Foundation, bien de la versión 3 de dicha Licencia o bien (según su elección) de cualquier versión posterior. Este programa se distribuye con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA, incluso sin la garantía MERCANTIL implícita o sin garantizar la CONVENIENCIA PARA UN PROPÓSITO PARTICULAR. Para más detalles, véase la Licencia Pública General de GNU. Debería haber recibido una copia de la Licencia Pública General junto con este programa. En caso contrario, escriba a la Free Software Foundation, Inc., en 675 Mass Ave, Cambridge, MA 02139, EEUU. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <SNL/SNL.h> /*tipo de variable enumeracion para especificar un color de algo que el programa debe comunicar al usuario*/ typedef enum color {NoColor, normal, rojo, cyan, verde, azul, negro, amarillo, \ blanco, gris_claro, marron, purpura, gris_oscuro, verde_claro, cyan_claro, \ rojo_claro, purpura_claro} color; /*funcion que manda a la terminal secuencias de escape ANSI para borrar la pantalla y colocar el cursor al comienzo de la misma*/ int secuencia_borrar_terminal(); /*funcion que manda a la terminal secuencias de escape ANSI para dar formato de color al texto en la terminal (el cambio se mantiene hasta que se vuelva a cambiar)*/ int secuencia_color_terminal(color c); int main(int argc, char *argv[]){ /*iniciamos las variables*/ int conexion, conexion_escucha, puerto, e=0, i=0, p=1; unsigned long int numero_clientes=0; char buffer[1537], direccion[21]; /* Esta sera la publicidad que mostrara el servidor*/ char publicidad[]="\n\nPublicidad del servidor:\nVisita www.snl.ya.st\n\n\n\0"; /*el grupo de conexiones, con uno es suficiente*/ grupo_conexiones *clientes; /*esto es puramente por decoracion y que quede bonito, solo borra la ventana de la terminal*/ secuencia_borrar_terminal(); /*escribimos en pantalla*/ printf("Conectando el servidor en el puerto 1500, espere."); /*iniciamos una conexion de escucha (este ejemplo es usando IPv4, pero con IPv6 es practicamente igual pero usando las funciones que no acaban con _IPv4 el nombre de la funcion, consulte la documentacion para más información*/ conexion_escucha= SNL_escuchar_TCP_IPv4(NULL, 1500, 20); /*comprobamos que el servidor este conectado*/ if(conexion == SIN_CONEXION){ /*esta es otra funcion que simplemente es para que quede bonito el ejemplo, imprime en pantalla una secuencia de escape ANSI que hace que todo lo que se escriba despues se vea en rojo claro*/ secuencia_color_terminal(rojo_claro); printf("Error iniciando la conexion del servidor en el puerto 1500.\n"); /*con esto hacemos que al escribir no se escriba en rojo en pantalla sino en el color predeterminado*/ secuencia_color_terminal(NoColor); return -1; }else{ printf("Servidor conectado y aceptando clientes en el puerto "); secuencia_color_terminal(cyan); printf("1500"); secuencia_color_terminal(NoColor); printf(".\n"); /*esto si nos interesa, iniciamos un nuevo grupo de conexiones pasando como argumento la conexion que usaremos para escuchar conexiones entrantes*/ clientes= SNL_nuevo_grupo_conexiones(conexion_escucha); /*comprobamos que se creara el nuevo grupo*/ if(clientes == NULL){ /*esto es que no se a creado, lo indicamos y acabamos el programa*/ secuencia_color_terminal(rojo_claro); printf("Error de memoria insuficiente.\n"); secuencia_color_terminal(NoColor); return -1; }else{ /*se creo correctamente el grupo, cambiamos el tiempo de espera a que suceda algo en los sockets del grupo a un segundo y 500000 microsegundos (un segundo y medio)*/ SNL_tiempo_espera_grupo(clientes, 1, 500000); /*esto es un bucle con el que estar atendiendo a los clientes continuamente sin que acabe el programa, deberemos acabarlo pulsando CONTROL+C o cerrando la terminal*/ while(e == 0){ printf("Comprobando conexiones entrantes, espere.\n"); /*comprobamos si hay alguna conexion entrante*/ while(SNL_conexion_entrante_grupo(clientes) == 1){ printf("Nueva conexion entrante, espere.\n"); /*aceptamos la conexion entrante como un buen servidor*/ conexion= SNL_aceptar_conexion_IPv4(conexion_escucha, &direccion[0], &puerto); /*comprobamos que se ha podido establecer la conexion*/ if(conexion == SIN_CONEXION){ secuencia_color_terminal(rojo_claro); printf("Error aceptando conexion entrante.\n"); secuencia_color_terminal(NoColor); }else{ printf("Conexion entrante nueva aceptada:\n"); secuencia_color_terminal(amarillo); printf("%s %i\n", &direccion[0], puerto); secuencia_color_terminal(NoColor); /*añadimos la conexion al grupo de conexiones y comprobamos que no hubo errores*/ if(SNL_nueva_conexion_grupo(conexion, clientes) != 0){ secuencia_color_terminal(rojo_claro); printf("Error de memoria en la conexion entrante.\n"); secuencia_color_terminal(NoColor); }else{ printf("La nueva conexion entrante ha sido aceptada sin problemas.\n"); /*aumentamos el numero de clientes*/ numero_clientes++; strcpy(&buffer[0], "Un cliente se ha conectado al servidor.\n"); strcat(&buffer[0], "IP del cliente que se ha conectado: "); strcat(&buffer[0], &direccion[0]); strcat(&buffer[0], "\n\0"); /*enviamos a todos los clientes la direccion IP del nuevo cliente y comprobamos que no hubo ningun error enviando*/ if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Datos reenviados a todos los clientes sin problemas.\n"); }else{ secuencia_color_terminal(rojo_claro); printf("Error reenviando datos a todos los clientes.\n"); secuencia_color_terminal(NoColor); } } } } printf("Conexiones entrantes comprobadas.\n"); printf("Comprobando clientes conectados en busca de actividad en la conexion, espere.\n"); conexion= SIN_CONEXION; /*comprobamos si hay alguna conexion activa en el grupo de conexiones*/ if(SNL_comprobar_grupo_conexiones(clientes) == 0){ /*ahora obtenemos la conexion activa del grupo*/ conexion= SNL_conexion_activa_grupo_conexiones(clientes); /*este bucle es para despues intentar obtener otra conexion activa hasta atender a todas*/ while(conexion > SIN_CONEXION){ /*vaciamos el buffer, esto no es relevante para el uso de SNL, pero como este programa lo probare usando telnet para conectarme a el consigo asi que al enviar un mensaje no muestre fragmentos de mensajes anteriores*/ for(i=0; i<1537; i++){ buffer[i]= '\0'; } /*recibimos los datos del cliente y guardamos el valor retornado*/ i= SNL_recibir_TCP(conexion, &buffer[0], 1536, 0); /*comprobamos que sucedio con el valor retornado*/ if(i == 0){ printf("Desconexion del cliente.\n"); /*quitamos la conexion del grupo como la funcion de recivir datos ya la cerro automaticamente*/ if(SNL_quitar_conexion_grupo(conexion, clientes) == 0){ printf("Conexion cerrada sin problemas.\n"); /*ahora tenemos un cliente menos conectado*/ numero_clientes--; strcpy(&buffer[0], "Un cliente se ha desconectado del servidor.\n\0"); /*informamos de esto a los demas clientes*/ if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Datos reenviados a todos los clientes sin problemas.\n"); }else{ secuencia_color_terminal(rojo_claro); printf("Error reenviando datos a todos los clientes.\n"); secuencia_color_terminal(NoColor); } }else{ secuencia_color_terminal(rojo_claro); printf("Error cerrando la conexion.\n"); secuencia_color_terminal(NoColor); numero_clientes--; strcpy(&buffer[0], "Un cliente se ha desconectado del servidor.\nOcurrio un error en la desconexion.\n\0"); if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Datos reenviados a todos los clientes sin problemas.\n"); }else{ secuencia_color_terminal(rojo_claro); printf("Error reenviando datos a todos los clientes.\n"); secuencia_color_terminal(NoColor); } } }else if(i == -1){ secuencia_color_terminal(rojo_claro); printf("Error recibiendo datos del cliente.\n"); secuencia_color_terminal(NoColor); strcpy(&buffer[0], "Ocurrio un error reciviendo datos de un cliente.\n\0"); /*informamos a todos los clientes del error reciviendo los datos*/ if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Datos reenviados a todos los clientes sin problemas.\n"); }else{ secuencia_color_terminal(rojo_claro); printf("Error reenviando datos a todos los clientes.\n"); secuencia_color_terminal(NoColor); } }else{ printf("Datos recividos del cliente:\n"); secuencia_color_terminal(verde); printf("%s\n", &buffer[0]); secuencia_color_terminal(NoColor); printf("Reenviando datos a todos los clientes, espere.\n"); /*reenviamos los datos recividos a todos los clientes*/ if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Datos reenviados a todos los clientes sin problemas.\n"); /*esto es para despues mostrar publicidad*/ p++; }else{ secuencia_color_terminal(rojo_claro); printf("Error reenviando datos a todos los clientes.\n"); secuencia_color_terminal(NoColor); } } /*este es el motivo del while dentro del que estamos, comprobamos nuevamente las conexiones activas para atender a todas*/ conexion= SIN_CONEXION; SNL_comprobar_grupo_conexiones(clientes); conexion= SNL_conexion_activa_grupo_conexiones(clientes); } } printf("Actividad en las conexiones comprobadas.\n"); /*esto se encarga de la publicidad*/ if(p >= 20){ p= 1; strcpy(&buffer[0], &publicidad[0]); strcat(&buffer[0], "Datos del servidor:\n - Ultima IP conectada: "); strcat(&buffer[0], &direccion[0]); strcat(&buffer[0], "\n\n\n\0"); if(SNL_enviar_grupo_TCP(clientes, &buffer[0], 1536, 0) == 0){ printf("Publicidad enviada a todos los clientes sin problemas.\n"); }else{ secuencia_color_terminal(rojo_claro); printf("Error enviando publicidad a todos los clientes.\n"); secuencia_color_terminal(NoColor); } } /*esto es tambien para que quede bonito, y para evitar consumir demasiada CPU, para el programa 1 segundo, esto en GNU/Linux funciona, pero en otros sistemas no puedo asegurarlo, como no es relevante puede eliminarse para compilar si da error solo que la pantalla de la terminal parpadeara al borrar el texto y escribir nuevamente*/ sleep(1); secuencia_borrar_terminal(); printf("Servidor conectado y aceptando clientes en el puerto "); secuencia_color_terminal(cyan); printf("1500"); secuencia_color_terminal(NoColor); printf(".\n"); printf("Total de clientes conectados: "); secuencia_color_terminal(cyan); printf("%lu", numero_clientes); secuencia_color_terminal(NoColor); printf(".\n"); printf("Ultimos datos recividos del cliente:\n"); secuencia_color_terminal(verde); printf("%s", &buffer[0]); secuencia_color_terminal(NoColor); printf("\n"); } return 0; } } } /*funcion que manda a la terminal secuencias de escape ANSI para borrar la pantalla y colocar el cursor al comienzo de la misma*/ int secuencia_borrar_terminal(){ printf("\n"); printf("%c[2J", 27); printf("%c[0;0f", 27); secuencia_color_terminal(normal); return 0; } /*funcion que manda a la terminal secuencias de escape ANSI para dar formato de color al texto en la terminal (el cambio se mantiene hasta que se vuelva a cambiar)*/ int secuencia_color_terminal(color c){ register int r=0; printf("%c[", 27); switch(c){ case rojo: printf("0;31"); break; case rojo_claro: printf("1;31"); break; case verde: printf("0;32"); break; case verde_claro: printf("1;32"); break; case amarillo: printf("1;33"); break; case marron: printf("0;33"); break; case gris_oscuro: printf("1;30"); break; case gris_claro: printf("0;37"); break; case azul: printf("0;34"); break; case purpura: printf("0;35"); break; case purpura_claro: printf("1;35"); break; case cyan: printf("0;36"); break; case cyan_claro: printf("1;36"); break; case blanco: printf("1;37"); break; default: printf("0;00"); break; } printf("m"); return r; }
[editar] Enlaces externos
- www.snl.ya.st - Página oficial de SNL.

