<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog OpenAlfa</title>
	<atom:link href="https://blog.openalfa.com/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.openalfa.com</link>
	<description>Diario del proyecto OpenAlfa</description>
	<lastBuildDate>Tue, 30 Jan 2018 12:43:35 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.3.2</generator>
	<item>
		<title>Cómo leer y escribir datos binarios en un fichero en C</title>
		<link>https://blog.openalfa.com/como-leer-y-escribir-datos-binarios-en-un-fichero-en-c</link>
				<comments>https://blog.openalfa.com/como-leer-y-escribir-datos-binarios-en-un-fichero-en-c#respond</comments>
				<pubDate>Wed, 08 Nov 2017 09:52:08 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7304</guid>
				<description><![CDATA[Una de las razones para realizar el desarrollo de una aplicación en lenguaje C en lugar de otros lenguajes como Java o PHP, es la necesidad de obtener el máximo rendimiento de los recursos hardware disponibles. En este sentido, la entrada/salida de datos a ficheros puede ser un factor importante. En desarrollos que no sean <a href='https://blog.openalfa.com/como-leer-y-escribir-datos-binarios-en-un-fichero-en-c' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Una de las razones para realizar el desarrollo de una aplicación en lenguaje C en lugar de otros lenguajes como Java o PHP, es la necesidad de obtener el máximo rendimiento de los recursos hardware disponibles.</p>
<p>En este sentido, la entrada/salida de datos a ficheros puede ser un factor importante. En desarrollos que no sean críticos en tiempo de ejecución, es habitual utilizar formatos estructurados como XML o JSON para almacenar los datos. Pero el proceso de conversión hacia y desde estos formatos consume recursos. Para optimizar el rendimiento, podemos optar por almacenar los datos en formato binario, como se explica en este artículo.</p>
<p><span id="more-7304"></span></p>
<h2>Apertura de un fichero de datos binarios</h2>
<p>La apertura del fichero se realiza con una llamada a fopen(), pasando como argumentos el nombre del fichero, y un flag «rb» o «wb» según se vaya a abrir el fichero en modo de lectura o de escritura.</p>
<p>La función fopen devuelve un puntero a un descriptor de fichero, que será pasado como argumento a las llamadas que se realicen para acceder a los datos del fichero. Por ejemplo:</p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;

int main (int argc, char *argv[]) {

    FILE *fh = fopen("datos.dat","wb");

    ... 
}</pre><p></p>
<h2>Escritura de variables de tipo entero y punto flotante</h2>
<p>Para escribir variables integer, float y double en un fichero de datos binario se utiliza la función fwrite, a la que se le pasan como argumentos:</p>
<ul>
<li>Un puntero a la variable a escribir que se puede obtener con el operador «&amp;».</li>
<li>el número de bytes que ocupa la variable. Para obtener este valor, lo más sencillo es utiizar la función sizeof. En el caso de un array, el número de bytes que ocupa cada uno de los elementos del array.</li>
<li>El tercer argumento 1 para variables sencillas. Si se está escribiendo un array, es el número de elementos del array.</li>
<li>El puntero al descriptor del fichero en donde se van a escribir los datos.</li>
</ul>
<p>Ejemplo:</p><pre class="crayon-plain-tag">int dato;
    dato = 1;

    fwrite( &amp;dato, sizeof dato, 1, fh);</pre><p>Ejemplo de escritura de un array:</p><pre class="crayon-plain-tag">int datos[1024];
    datos[0] = 1;
    datos[1] = 7;
    ...
    fwrite(&amp;datos[0],sizeof datos[0], 1024, fh);</pre><p></p>
<h2>Escritura de variables de tipo string</h2>
<p>Para escribir una cadena de texto se utiliza una llamada a fwrite() como en el caso de variables de tipo entero, con la diferencia de que en lugar de utilizar «sizeof», podemos utilizar la función strlen() para obtener el número de bytes a escribir.</p>
<p>Por otra parte, aunque podríamos escribir el carácter «NULL» (0) para marcar el fin de la cadena de texto, puede resultar más conveniente escribir un valor entero precediendo a la cadena de texto, que indique la longitud de la misma.</p>
<p>Ejemplo:</p><pre class="crayon-plain-tag">char *texto;
    int nbytes; 

    texto = "Esto es un texto de prueba";
    nbytes = strlen(texto);

    fwrite (&amp;nbytes, sizeof nbytes, 1, fh);
    fwrite (texto, nbytes, 1, fh);</pre><p></p>
<h2>Lectura de los datos de un fichero binario</h2>
<p>Para leer los datos contenidos en un fichero binario, abrimos primero el fichero con una llamada a fopen(), con el flag «rb».</p>
<p>A continuación, utilizamos simplemente la función fread(), que recibe los mismos argumentos que la función fwrite().</p>
<p>Por ejemplo, para leer un número entero:</p><pre class="crayon-plain-tag">FILE *fh = fopen("datos.dat","rb");

    fread (&amp;dato, sizeof dato, 1, fh);</pre><p>Para leer un string, si el string está precedido por un valor entero que indica su longitud, podemos utilizar el siguiente código:</p><pre class="crayon-plain-tag">int nbytes;
    char *texto;
    fread (&amp;nbytes, sizeof nbytes, 1, fh);
    texto = (char *)malloc(nbytes+1);
    fread (texto, nbytes, 1, fh);
    texto[nbytes] = 0;

    printf("Texto leido: %s\n",texto);</pre><p>Como vemos:</p>
<ul>
<li>Comenzamos leyendo en la variable &#8216;nbytes&#8217; la longitud del string</li>
<li>Mediante una llamada a malloc(), asignamos a la variable &#8216;texto&#8217; un buffer para contener el string. El tamaño del buffer es nbytes+1, para poder incluir el carácter NULL que marca el fin del string</li>
<li>Leemos el texto en la variable &#8216;texto&#8217;</li>
<li>Asignamos el caracter NULL al último byte del buffer.</li>
</ul>
<p>&#8212;</p>
<p>Referencias:</p>
<ul>
<li><a href="https://www.programiz.com/c-programming/c-file-input-output">C Programming Files I/O</a></li>
</ul>
<p>&#8212;-</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-leer-y-escribir-datos-binarios-en-un-fichero-en-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo solucionar el aviso «Eliminate Render blocking CSS» de Google PageSpeed Insights</title>
		<link>https://blog.openalfa.com/como-solucionar-el-aviso-eliminate-render-blocking-css-de-google-pagespeed-insights</link>
				<comments>https://blog.openalfa.com/como-solucionar-el-aviso-eliminate-render-blocking-css-de-google-pagespeed-insights#respond</comments>
				<pubDate>Tue, 31 Oct 2017 17:10:20 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7298</guid>
				<description><![CDATA[La herramienta «Page Speed Insights» que ofrece Google permite analizar muchos aspectos que influyen en el tiempo total de carga de una página web en el navegador del usuario. El tiempo de carga es un factor importante porque influye directamente en la experiencia del usuario, y también es una señal que utiliza el buscador de <a href='https://blog.openalfa.com/como-solucionar-el-aviso-eliminate-render-blocking-css-de-google-pagespeed-insights' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>La herramienta «Page Speed Insights» que ofrece Google permite analizar muchos aspectos que influyen en el tiempo total de carga de una página web en el navegador del usuario.</p>
<p>El tiempo de carga es un factor importante porque influye directamente en la experiencia del usuario, y también es una señal que utiliza el buscador de Google para el posicionamiento de la página en la lista de resultados.</p>
<p>Uno de los consejos que pueden aparecer cuando se analiza una página web en PageSpeed Insights es «Eliminate Render blocking CSS». En este artículo vamos a presentar un procedimiento para eliminar este aviso y aumentar la puntuación que PageSpeed Insights asigna a la página.</p>
<p><span id="more-7298"></span></p>
<h2>Carga no bloqueante del código CSS de la página</h2>
<p>Un página web típica utiliza una o varias hojas de estilo CSS a las que hace referencia mediante una serie de tags «&lt;link&gt;» incluidos en la cabecera del código HTML. Por ejemplo:</p><pre class="crayon-plain-tag">&lt;html&gt;
&lt;head&gt;
...
  &lt;link href="/css/combined.css" rel="stylesheet" media="screen"&gt; 
  &lt;link href="/css/bootstrap.min.css" rel="stylesheet" media="screen"&gt; 
  &lt;link href="/css/font-awesome.css" rel="stylesheet"&gt; 
  &lt;link href="/css/jquery.nstSlider.min.css" rel="stylesheet" media="screen"&gt;
  &lt;link href="/css/selectboxit.css" rel="stylesheet" media="screen"&gt;
...</pre><p>Cuando el navegador web comienza a procesar la página, al encontrarse con estos tags realiza la descarga de los ficheros css especificados, y espera a que estén descargados antes de continuar el proceso.</p>
<p>Para evitar este comportamiento, se puede solicitar la carga de las hojas de estilo con un código distinto:</p><pre class="crayon-plain-tag">...
  &lt;link href="/css/combined.css" rel="preload" media="screen" as="style"
        onload="this.rel='stylesheet'"&gt;
  &lt;noscript&gt;
    &lt;link href="/css/combined.css" rel="stylesheet" media="screen"&gt;
  &lt;/noscript&gt;
  &lt;link href="/css/bootstrap.min.css" rel="preload" media="screen" as="style"
        onload="this.rel='stylesheet'"&gt;
  &lt;noscript&gt;
    &lt;link href="/css/bootstrap.min.css" rel="stylesheet" media="screen"&gt;
  &lt;/noscript&gt;
...</pre><p>Como vemos, en este caso se carga la hoja de estilo con el atributo &#8216;rel=»preload»&#8216;, y sólo después de cargada se cambia este atributo mediante javascript (onload=»this.rel=&#8217;stylesheet'»).</p>
<p>Para considerar el caso de navegadores que no soportan javascript, se añade un bloque &lt;noscript&gt;&#8230;&lt;/noscript&gt; en el que se incluye también la carga «normal» de la hoja des estilo.</p>
<p>Con este cambio, la carga de las hojas de estilo deja de ser bloqueante, como se puede comprobar volviendo a analizar la página con Google Page Speed Insights.</p>
<p>El problema que se presenta al aplicar este cambio es que en este caso el navegador presenta primero el contenido de la página antes de haber aplicado ningún estilo. Después de descargar las hojas CSS, aplica los estilos y vuelve a presentar la página en pantalla, lo que provoca un efecto indeseable.</p>
<h2>Identificación del código CSS «crítico»</h2>
<p>Para evitar este efecto, se puede incluir «inline» en el propio código HTML de la página (entre los tags &lt;style&gt;&#8230;&lt;/style&gt;), el conjunto mínimo de código CSS que permite la visualización definitiva de la parte visible de la página.</p>
<p>Pero identificar manualmente este código CSS es una tarea tremendamente laboriosa. Afortunadamente, existen aplicaciones que permiten automatizar este trabajo. En este artículo, vamos a utilizar la aplicación «Critical» de github (https://github.com/addyosmani/critical).</p>
<h2>Instalación de npm</h2>
<p>El package manager «npm» se instala como parte del paquete «nodejs».</p>
<p>La manera más sencilla de obtener la versión más reciente de Node.js es añadir el PPA (personal package archive) mantenido por NodeSource.<br />
Este repositorio contiene versiones de Node.js más actualizadas que las existentes en los repositorios oficiales de Debian.</p>
<p>En primer lugar, añadimos el PPA de NodeSource:</p><pre class="crayon-plain-tag">$ curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh
$ sudo bash nodesource_setup.sh</pre><p>Y a continuación realizamos la instalación del paquete nodejs</p><pre class="crayon-plain-tag">$ sudo apt-get install nodejs</pre><p>Por último, comprobamos las versiones de nodejs y npm instaladas:</p><pre class="crayon-plain-tag">$ nodejs --version
v6.11.5
lokku@ip-172-31-12-45:~$ npm --version
3.10.10</pre><p></p>
<h2>Instalación de critical</h2>
<p>La aplicacion se instala con el package manager «npm»:</p><pre class="crayon-plain-tag">$ sudo npm install -g critical</pre><p></p>
<h2>Ejecución de critical y obtención del código CSS crítico</h2>
<p>Con esto, ya estamos en condiciones de analizar el contenido de una página web de nuestro site, para obtener el código CSS crítico.</p>
<p>En primer lugar descargamos el código html de la página, utilizando por ejemplo el comando wget:</p><pre class="crayon-plain-tag">$ wget -O pru.html http://www.ejemplo.com/pagina-a-optimizar</pre><p>y después realizamos el análisis:</p><pre class="crayon-plain-tag">$ critical pru.html --base /var/www --inline &gt; pru.critical.html</pre><p>La opción «&#8211;base /var/www» indica la ubicación del «DocumentRoot» del sitio, y es utilizada por la aplicación «critical» para obtener los ficheros auxiliares (imágenes, ficheros javascript, hojas de estilo css,&#8230;) utilizados por la página. Deberemos sustituir el valor /var/www por el que corresponda para el sitio web que está siendo analizado.</p>
<p>El fichero pru.critical.html generado contiene en el interior del header un bloque &lt;style type=»text/css»&gt;&#8230;&lt;/style&gt; con el código CSS crítico para la visualización de la página.</p>
<p>Ya sólo nos queda incorporar dicho código en las páginas de nuestro site, y comprobar el resultado.</p>
<p>Hay que tener en cuenta que el código CSS crítico puede ser distinto para cada una de las páginas del sitio.</p>
<h4>Referencias</h4>
<ul>
<li class="entry-title"><a href="https://vuejsdevelopers.com/2017/07/24/critical-css-webpack/">Critical CSS and Webpack: Automatically Minimize Render-Blocking CSS</a></li>
<li class="content-title Tutorial-header"><a href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-debian-8">How To Install Node.js on Debian 8</a></li>
<li><a href="https://linuxconfig.org/how-to-install-nodejs-on-debian-9-stretch-linux">How to Install NodeJS on Debian 9 Stretch Linux</a></li>
<li class="content-title Tutorial-header"><a href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-16-04">How To Install Node.js on Ubuntu 16.04</a></li>
</ul>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-solucionar-el-aviso-eliminate-render-blocking-css-de-google-pagespeed-insights/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo leer un fichero línea a línea en lenguaje C</title>
		<link>https://blog.openalfa.com/como-leer-un-fichero-linea-a-linea-en-lenguaje-c</link>
				<comments>https://blog.openalfa.com/como-leer-un-fichero-linea-a-linea-en-lenguaje-c#respond</comments>
				<pubDate>Tue, 24 Oct 2017 14:27:13 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7286</guid>
				<description><![CDATA[Para leer en C un fichero de texto ‘fichero.txt’ y procesarlo línea a línea, podemos escribir un programa «lee_fichero.c» conteniendo el siguiente código: [crayon-5f82b99e8e27c828714616/] A continuación, compilamos el programa: [crayon-5f82b99e8e286216038553/] Y por último lo ejecutamos. Si el fichero de texto a leer «fichero.txt» contiene las líneas: [crayon-5f82b99e8e28a836443894/] al ejecutar el script desde la línea de <a href='https://blog.openalfa.com/como-leer-un-fichero-linea-a-linea-en-lenguaje-c' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Para leer en C un fichero de texto ‘fichero.txt’ y procesarlo línea a línea, podemos escribir un programa «lee_fichero.c» conteniendo el siguiente código:</p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;

int main() {

    char linea[1024];
    FILE *fich;

    fich = fopen("fichero.txt", "r");
    //Lee línea a línea y escribe en pantalla hasta el fin de fichero
    while(fgets(linea, 1024, (FILE*) fich)) {
        printf("LINEA: %s FIN_DE_LINEA\n", linea);
    }
    fclose(fich);
}</pre><p>A continuación, compilamos el programa:</p><pre class="crayon-plain-tag">$ gcc -o lee_fichero lee_fichero.c</pre><p>Y por último lo ejecutamos.</p>
<p>Si el fichero de texto a leer «fichero.txt» contiene las líneas:</p><pre class="crayon-plain-tag">Linea primera
Linea segunda
Linea tercera</pre><p>al ejecutar el script desde la línea de comandos, obtendremos lo siguiente:</p><pre class="crayon-plain-tag">$ ./lee_fichero
LINEA: Linea primera
 FIN_DE_LINEA
LINEA: Linea segunda
 FIN_DE_LINEA
LINEA: Linea tercera
 FIN_DE_LINEA
$</pre><p></p>
<h2>NOTAS</h2>
<h3>Carácter de fin de línea</h3>
<p>Como podemos ver en la salida generada por el programa de ejemplo, cada línea leída incluye el carácter de fin de línea &#8216;\n&#8217;. Si deseamos eliminarlo, podemos simplemente añadir dentro del bucle las sentencias:</p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
...
while(fgets(linea, 1024, (FILE*) fich)) {
    int n = strlen(linea);
    linea[n-1] = 0;
    ...
}
...</pre><p></p>
<h3>Tamaño del buffer de lectura.</h3>
<p>En el código de ejemplo, para leer las líneas, hemos creado un buffer de 1024 bytes con la sentencia «char linea[1024];». En la llamada a fgets, le pasamos como segundo argumento el tamaño del buffer.</p>
<p>Esto nos permite leer líneas de hasta 1022 (1024-2) caracteres, ya que es necesario un byte adicional para almacenar el carácter de fin de línea (&#8216;\n&#8217;), y otro para el caracter nulo (0) que finaliza la cadena de texto.</p>
<p>Si el fichero a leer contiene líneas de mayor tamaño, deberemos dimensionar adecuadamente el buffer.</p>
<p>Podemos añadir al código una condición para comprobar si se da el caso de que una línea del fichero leído es mayor que el tamaño del buffer:</p><pre class="crayon-plain-tag">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
...
while(fgets(linea, 1024, (FILE*) fich)) {
    int n = strlen(linea);
    if (linea[n-1] != '\n') {
        printf ("Error. leída línea incompleta\n");
    }
    ...
}
...</pre><p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-leer-un-fichero-linea-a-linea-en-lenguaje-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo usar expresiones regulares en Java</title>
		<link>https://blog.openalfa.com/como-usar-expresiones-regulares-en-java</link>
				<comments>https://blog.openalfa.com/como-usar-expresiones-regulares-en-java#respond</comments>
				<pubDate>Sat, 19 Nov 2016 13:31:44 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7217</guid>
				<description><![CDATA[Las expresiones regulares son una poderosa herramienta para el proceso de muchos tipos de datos. En Java también es posible utilizar expresiones regulares, como se explica en este artículo. Determinar si una cadena contiene un patrón especificado en forma de expresión regular La funcionalidad para el tratamiento de expresiones regulares en Java está implementada en <a href='https://blog.openalfa.com/como-usar-expresiones-regulares-en-java' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Las expresiones regulares son una poderosa herramienta para el proceso de muchos tipos de datos.</p>
<p>En Java también es posible utilizar expresiones regulares, como se explica en este artículo.</p>
<p><span id="more-7217"></span></p>
<h2>Determinar si una cadena contiene un patrón especificado en forma de expresión regular</h2>
<p>La funcionalidad para el tratamiento de expresiones regulares en Java está implementada en el paqueta java.util.regex.</p>
<p>Este paquete contiene las clases «Pattern» y «Matcher».</p>
<p>Con la clase Pattern creamos un objeto correspondiente a un determinado patrón (expresión regular) que queremos utilizar en el programa. Por ejemplo:</p><pre class="crayon-plain-tag">Pattern p = Pattern.compile(&quot;a*b&quot;);</pre><p>La clase Matcher implementa el método «matches()», con el cual podemos comprobar si una determinada cadena de texto cumple con la expresión regular:</p><pre class="crayon-plain-tag">Matcher m = p.matcher(&quot;aaaaab&quot;);
 boolean b = m.matches();</pre><p>Por conveniencia, la clase Pattern también implementa un método estático «matches()», que compila la expresión regular, crea una instancia de la clase Matcher, y llama a su método matches(). De este modo, las tres sentencias del ejemplo anterior se pueden escribir como una única sentencia:</p><pre class="crayon-plain-tag">boolean b = Pattern.matches(&quot;a*b&quot;, &quot;aaaaab&quot;);</pre><p></p>
<h2>Sustituir con una subcadena las ocurrencias de un patrón en una cadena de texto</h2>
<p>Para realizar la sustitución de la primera ocurrencia de la expresión regular, se utiliza el método replaceFirst() de la clase Matcher.</p>
<p>También podemos utilizar el método replaceAll() para sustituir todas las ocurrencias del patrón.</p>
<p>Ejemplo:</p><pre class="crayon-plain-tag">Pattern p = Pattern.compile(&quot;(verde|rojo)&quot;);
        Matcher m = p.matcher(&quot;amarillo, rojo, morado, verde, naranja&quot;);
        String resultado = m.replaceFirst(&quot;azul&quot;);
        System.out.println(&quot;Colores: &quot; + resultado);
        resultado = m.replaceAll(&quot;azul&quot;);
        System.out.println(&quot;Colores: &quot; + resultado);</pre><p>El código del ejemplo genera la siguiente salida:</p><pre class="crayon-plain-tag">Colores: amarillo, azul, morado, verde, naranja
Colores: amarillo, azul, morado, azul, naranja</pre><p></p>
<h2>Grupos de captura</h2>
<p>La expresión regular puede contener grupos de captura encerrados entre paréntesis.</p>
<p>Después de aplicar el patrón (con el método «find()») a una cadena de texto, el método group(n) permite recuperar las subcadenas coindicientes con cada uno de los grupos de captura presentes en la expresión regular. Por ejemplo:</p><pre class="crayon-plain-tag">p = Pattern.compile(&quot;([^ ]*) ([^ ]*) (.*)&quot;);
        m = p.matcher(&quot;uno dos tres cuatro cinco&quot;);
        if (m.find()) {
            System.out.println(&quot;grupo A: &quot; + m.group(1));
            System.out.println(&quot;grupo B: &quot; + m.group(2));
            System.out.println(&quot;grupo C: &quot; + m.group(3));
        }</pre><p>En este ejemplo, la subcadena correspondiente al grupo $1 es «uno», $2 es «dos» y $3 es «tres cuatro cinco». El resultado que se presenta en pantalla es:</p><pre class="crayon-plain-tag">grupo A: uno
grupo B: dos
grupo C: tres cuatro cinco</pre><p>Mediante la expresión «$n» (en donde n es el número de secuencia del grupo), las subcadenas correspondientes a los grupos de captura pueden ser utilizadas en el argumento de los métodos replaceFirst() y replaceAll(). Por ejemplo:</p><pre class="crayon-plain-tag">p = Pattern.compile(&quot;([^ ]*) ([^ ]*) (.*)&quot;);
        m = p.matcher(&quot;uno dos tres cuatro cinco&quot;);
        resultado = m.replaceFirst(&quot;$3 - $2 - $1&quot;);
        System.out.println(&quot;Resultado: &quot; + resultado);</pre><p>Al ejecutar estass sentencias, el resultado que se presenta en pantalla es:</p><pre class="crayon-plain-tag">Resultado: tres cuatro cinco - dos - uno</pre><p></p>
<h4>Referencias</h4>
<p>JavaDoc &#8211; <a href="https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html">java.util.regex.Pattern</a></p>
<p>&#8212;</p>
<p><a title="Indice de artículos sobre programación en Java" href="/indice-de-articulos-sobre-programacion-en-java/">Indice de artículos sobre programación en lenguaje Java</a></p>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-usar-expresiones-regulares-en-java/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo instalar y configurar un certificado SSL de Let&#8217;s Encrypt en Debian/Ubuntu+Apache web server</title>
		<link>https://blog.openalfa.com/como-instalar-y-configurar-un-certificado-ssl-de-lets-encrypt-en-debianubuntu-y-apache-web-server</link>
				<comments>https://blog.openalfa.com/como-instalar-y-configurar-un-certificado-ssl-de-lets-encrypt-en-debianubuntu-y-apache-web-server#respond</comments>
				<pubDate>Fri, 19 Aug 2016 08:03:03 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Admon. Servidores]]></category>
		<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7155</guid>
				<description><![CDATA[Históricamente, la necesidad de implementar un protocolo seguro de comunicación entre un cliente y un servidor web sólo se presentaba para sitios que manejaban datos confidenciales de los usuarios, como por ejemplo las tiendas online. Sin embargo, desde que Google anunció a mediados de 2014 que el uso del protocolo seguro https iba a ser <a href='https://blog.openalfa.com/como-instalar-y-configurar-un-certificado-ssl-de-lets-encrypt-en-debianubuntu-y-apache-web-server' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Históricamente, la necesidad de implementar un protocolo seguro de comunicación entre un cliente y un servidor web sólo se presentaba para sitios que manejaban datos confidenciales de los usuarios, como por ejemplo las tiendas online. Sin embargo, desde que Google anunció a mediados de 2014 que <a href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html">el uso del protocolo seguro https iba a ser tenido en cuenta por el algoritmo que determina el posicionamiento (ranking) de las páginas en los resultados de búsqueda</a>, cada vez son más los administradores de sitios web que se plantean la conveniencia de implementar este protocolo.</p>
<p>Para ello, hay que instalar y configurar un certificado SSL en el servidor. El proceso de solicitar un certificado, instalarlo y configurarlo ha sido tradicionalmente engorroso, y además era necesario adquirir el certificado desembolsando una cierta cantidad de dinero. La iniciativa Let&#8217;s Encrypt (promovida por Google), ha venido a solucionar este problema.</p>
<p>En este artículo se explica el procedimiento de instalación y configuración de un certificado SSL de Let&#8217;s Encrypt sobre un servidor Debian/Ubuntu que ejecuta un servidor web Apache.</p>
<p><span id="more-7155"></span></p>
<h2>Instalación del software</h2>
<p>Comenzamos por actualizar  el sistema, e instalar el paquete git para poder acceder al repositorio de Let&#8217;s Encrypt</p><pre class="crayon-plain-tag">sudo apt-get update
sudo apt-get install git</pre><p>A continuación, instalamos el software Let&#8217;s Encrypt bajo el directorio «/opt/letsencrypt»:</p><pre class="crayon-plain-tag">sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt</pre><p></p>
<h2>Configuración de apache</h2>
<p>Exceptuando los casos más sencillos, la configuración más habitual de los servidores web utiliza el mecanismo de «VirtualHosts» para albergar más de un dominio en un mismo servidor.</p>
<p>Normalmente, el dominio principal es de la forma «www.ejemplo.com», pero también pueden existir subdominios como por ejemplo «blog.ejemplo.com», etc. Además, es conveniente configurar también el dominio base «ejemplo.com», que suele ser redirigido con una redirección permanente 301 al dominio principal «www.ejemplo.com».</p>
<p>Actualmente, el procedimiento de instalación de certificado SSL de Let&#8217;s Encrypt no permite que haya más de un VirtualHost en un mismo fichero de configuración, por lo que deberemos crear bajo el directorio «/etc/apache2/sites-available» un fichero para cada uno de ellos:</p>
<p>/etc/apache2/sites-available/www.ejemplo.com.conf &#8211; Dominio principal</p><pre class="crayon-plain-tag">&lt;VirtualHost *:80&gt;
    ServerName www.ejemplo.conf
    ...
&lt;/VirtualHost&gt;</pre><p>/etc/apache2/sites-available/blog.ejemplo.com.conf &#8211; Subdominio para el blog</p><pre class="crayon-plain-tag">&lt;VirtualHost *:80&gt;
    ServerName blog.ejemplo.conf
    ...
&lt;/VirtualHost&gt;</pre><p>/etc/apache2/sites-available/ejemplo.com.conf &#8211; Dominio base, que simplemente contiene una redirección a www.ejemplo.com</p><pre class="crayon-plain-tag">&lt;VirtualHost *:80&gt;
    ServerName ejemplo.com

    RewriteEngine On
    RewriteRule ^/(.*)$ https://www.ejemplo.com/$1 [L,R=301]

&lt;/VirtualHost&gt;</pre><p></p>
<h2>Generación e instalación del certificado</h2>
<p>Una vez preparada la configuración de apache, creamos el certificado, incluyendo el dominio principal y todos los subdominios a los que se aplica:</p><pre class="crayon-plain-tag">cd /opt/letsencrypt</pre><p></p><pre class="crayon-plain-tag">./letsencrypt-auto --apache -d ejemplo.com -d www.ejemplo.com -d blog.ejemplo.com</pre><p>Al finalizar, se presenta el siguiente mensaje:</p><pre class="crayon-plain-tag"> - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/ejemplo.com/fullchain.pem. Your cert will
   expire on 2016-11-22. To obtain a new or tweaked version of this
   certificate in the future, simply run letsencrypt-auto again with
   the "certonly" option. To non-interactively renew *all* of your
   certificates, run "letsencrypt-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le</pre><p>Comprobamos que la instalación del certificado ha realizado algunas modificaciones en los ficheros de configuración de apache:</p>
<ul>
<li>En el fichero de configuración de cada dominio, añade una redirección 301 permanente de http a https:<br />
<pre class="crayon-plain-tag">&lt;VirtualHost *:80&gt;
    ServerName www.ejemplo.conf
    ...
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =www.ejemplo.conf
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
&lt;/VirtualHost&gt;</pre>
</li>
<li>También crea para cada dominio un fichero de configuración específico para el acceso por SSL, en el que incluye las directrices de configuración del certificado SSL:<br />
/etc/apache2/sites-available/www.ejemplo.com-le-ssl.conf<br />
<pre class="crayon-plain-tag">&lt;IfModule mod_ssl.c&gt;
&lt;VirtualHost *:443&gt;
    ServerName www.ejemplo.conf
    ...
    SSLCertificateFile /etc/letsencrypt/live/ejemplo.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ejemplo.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
&lt;/VirtualHost&gt;
&lt;/IfModule&gt;</pre>
</li>
</ul>
<h2>Verificación</h2>
<p>La configuración del sitio se puede comprobar haciendo uso del servicio online de ssllabs.com:</p><pre class="crayon-plain-tag">https://www.ssllabs.com/ssltest/analyze.html?d=www.ejemplo.conf</pre><p></p>
<h2>Renovación del certificado</h2>
<p>La renovación de todos los certificados SSL instalados en el servidor se realiza ejecutando el comando letsencript-auto con la opción «renew»:</p><pre class="crayon-plain-tag">root@servidor:/# cd /opt/letsencrypt/
root@oservidor:/opt/letsencrypt# ./letsencrypt-auto renew

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/ejemplo.com.conf
-------------------------------------------------------------------------------

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/ejemplo.com/fullchain.pem (skipped)
No renewals were attempted.</pre><p>Como vemos, se puede ejecutar el comando en cualquier momento, porque si los certificados no necesitan ser renovados no realiza ninguna acción.</p>
<p>Para automatizar la renovación, basta con introducir el comando como una entrada en crontab del usuario root:</p><pre class="crayon-plain-tag">30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew &gt;&gt; /var/log/le-renew.log</pre><p></p>
<h2>Extensión del certificado a subdominios adicionales</h2>
<p>Para añadir un subdominio a un certificado, se ejecuta de nuevo el mismo comando con el que se generó el certificado original, añadiendo el nuevo subdominio, y utilizando la opción «&#8211;expand».</p>
<p>Por ejemplo, para añadir el subdominio «img.ejemplo.com» al certificado, utilizaremos el comando:</p><pre class="crayon-plain-tag">./letsencrypt-auto --expand --apache \
             -d ejemplo.com \
             -d www.ejemplo.com \
             -d blog.ejemplo.com \
             -d img.ejemplo.com</pre><p></p>
<h2>Instalación del certificado en otro tipo de servidor web</h2>
<p>Al pasarle la opción «&#8211;apache» al comando letsencrypt-auto, se actualiza automáticamente la configuración del servidor web para hacer uso del certificado generado.</p>
<p>Pero si estamos utilizando otro tipo de servidor, o queremos realizar manualmente las modificaciones necesarias en los ficheros de configuración del servidor web, podemos utilizar en su lugar la opción «certonly», junto con las opciones «&#8211;webroot» y «&#8211;webroot-path &lt;/path/del/documentroot&gt;».</p>
<p>Por ejemplo, si el DocumentRoot de nuestro dominio «ejemplo.com» es «/var/www/ejemplo.com», el comando a utilizar sería de la forma:</p><pre class="crayon-plain-tag">./letsencrypt-auto certonly --webroot --webroot-path /var/www/ejemplo.com \
        -d ejemplo.com \
        -d www.ejemplo.com \
        -d blog.ejemplo.com</pre><p>Atención: Durante el proceso de generación del certificado, el comando letsencrypt-auto crea un subdirectorio «.well-known/acme-challenge» bajo el directorio especificado en la opción webroot-path (el DocumentRoot), y deposita en el mismo una serie de ficheros de prueba, a los que después intenta acceder con urls de la forma «http://www.ejemplo.com/.well-known/acme-challenge/*».</p>
<p>Por esta razón, hay que asegurarse de que no haya ninguna sentencia en la configuración del servidor web que impida el acceso a ficheros en dicha ruta.</p>
<h4>Referencias</h4>
<ul>
<li class="entry-title taggedlink clearfix"><a href="https://blog.nexcess.net/2014/09/03/the-pros-and-cons-of-implementing-ssl-https/">The Pros And Cons Of Implementing SSL / HTTPS</a></li>
<li><a title="HTTPS as a ranking signal" href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html">Official Google Webmaster blog &#8211; HTTPS as a ranking signal</a></li>
<li><a title="HTTPS as a ranking signal" href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html">How to Set Up Let’s Encrypt Certificates for Multiple Apache Virtual Hosts on Ubuntu 14.04</a></li>
<li><a href="http://letsencrypt.readthedocs.io/en/latest/index.html">Certbot / Letsencrypt Documentation</a></li>
<li><a href="https://developers.google.com/web/updates/2016/04/geolocation-on-secure-contexts-only?hl=en">Geolocation API removed from unsecured origins in Chrome 50</a></li>
</ul>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-instalar-y-configurar-un-certificado-ssl-de-lets-encrypt-en-debianubuntu-y-apache-web-server/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo mover un repositorio subversion a otro servidor</title>
		<link>https://blog.openalfa.com/como-mover-un-repositorio-subversion-a-otro-servidor</link>
				<comments>https://blog.openalfa.com/como-mover-un-repositorio-subversion-a-otro-servidor#respond</comments>
				<pubDate>Thu, 23 Jun 2016 08:33:36 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Miscelánea]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7129</guid>
				<description><![CDATA[Mover un repositorio de subversion a otro servidor no es realmente difícil, sólo hay que seguir los pasos que indicamos en este artículo, para asegurar que los clientes siguen teniendo acceso al repositorio en su nueva ubicación. 1. Hacer un volcado del repositorio En primer lugar, utilizamos el comando svnadmin para realizar una copia de <a href='https://blog.openalfa.com/como-mover-un-repositorio-subversion-a-otro-servidor' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Mover un repositorio de subversion a otro servidor no es realmente difícil, sólo hay que seguir los pasos que indicamos en este artículo, para asegurar que los clientes siguen teniendo acceso al repositorio en su nueva ubicación.</p>
<p><span id="more-7129"></span></p>
<h2>1. Hacer un volcado del repositorio</h2>
<p>En primer lugar, utilizamos el comando svnadmin para realizar una copia de seguridad del repositorio:</p><pre class="crayon-plain-tag">$ svnadmin dump /path/to/repo &gt; reponame.dump</pre><p>Opcinalmente, podemos comprimir el fichero que contiene el volcado. Después, copiamos el fichero al nuevo servidor por cualquier procedimiento: ftp, scp, rsync,&#8230;</p>
<h2>2. crear y cargar el repositorio en su nueva ubicación</h2>
<p>En el servidor de destino, creamos un nuevo repositorio, y lo cargamos con la copia de seguridad. Utilizamos la opción «&#8211;force-uuid» para que el nuevo repositorio se cree con el mismo uuid que el repositorio original, de modo que los clientes no tengan problemas en seguir utilizando el repositorio en su nueva localización:</p><pre class="crayon-plain-tag">nuevoservidor$ svnadmin create /path/to/new/repo
nuevoservidor$ svnadmin load /path/to/new/repo --force-uuid &lt; reponame.dump</pre><p></p>
<h2>3. Indicar a los clientes la nueva ubicación del repositorio</h2>
<p>Por último, en cada una de las «working copies», actualizamos la ubicación del repositorio.</p>
<p>Opcionalmente, con el comando «svn info» podemos comprobar primero la ubicación que estaba utilizando la working copy.</p><pre class="crayon-plain-tag">cliente$ cd proyecto
cliente$ svn info | grep URL:
URL: file:///path/to/old/repo/trunk</pre><p>después, con el comando «svn relocate» cambiamos la ubicación:</p><pre class="crayon-plain-tag">cliente$ svn relocate svn+ssh://usuario@www.nuevoservidor.com/path/to/new/repo/trunk</pre><p>( Para distintos clientes, podemos especificar distintos protocolos de conexión: file:, svn+ssh:, http:,&#8230; en función de las características de nuestra instalación ).</p>
<p>Y eso es todo!</p>
<h4>Referencias</h4>
<ul>
<li class="title"><a href="http://svnbook.red-bean.com/en/1.8/svn.ref.svnadmin.html">svnadmin Reference</a></li>
<li><a href="http://svnbook.red-bean.com/en/1.8/svn.ref.svn.c.relocate.html">svn reference &#8211; svn relocate</a></li>
</ul>
<p>&#8212;</p>
<p>&nbsp;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-mover-un-repositorio-subversion-a-otro-servidor/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo conectarse a una base de datos MySQL desde un programa C en Linux</title>
		<link>https://blog.openalfa.com/como-conectarse-a-una-base-de-datos-mysql-desde-un-programa-c-en-linux</link>
				<comments>https://blog.openalfa.com/como-conectarse-a-una-base-de-datos-mysql-desde-un-programa-c-en-linux#respond</comments>
				<pubDate>Tue, 10 May 2016 16:04:50 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7086</guid>
				<description><![CDATA[La distribución estándar de MySQL incluye las librerías necesarias para conectarse a la base de datos desde un cliente escrito en lenguaje C, con la misma facilidad que desde un script Perl o PHP. Previamente, para desarrollar un programa en C, deberemos haber instalado el entorno de desarrollo habitual: compilador gcc, utilidad make, etc&#8230; Adicionalmente, <a href='https://blog.openalfa.com/como-conectarse-a-una-base-de-datos-mysql-desde-un-programa-c-en-linux' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>La distribución estándar de MySQL incluye las librerías necesarias para conectarse a la base de datos desde un cliente escrito en lenguaje C, con la misma facilidad que desde un script Perl o PHP.</p>
<p><span id="more-7086"></span></p>
<p>Previamente, para desarrollar un programa en C, deberemos haber instalado el entorno de desarrollo habitual: compilador gcc, utilidad make, etc&#8230;</p>
<p>Adicionalmente, deberemos instalar el paquete de desarrollo de cliente de MySQL, que incluye las librerías y ficheros header (*.h) necesarios:</p><pre class="crayon-plain-tag"># apt-get install libmysqlclient-dev</pre><p>A continuación, escribimos el programa de ejemplo «conexion_mysql.c», con el siguiente contenido (sustituyendo el literal «PASSWORD» por la contraseña del usuario root):</p><pre class="crayon-plain-tag">/* Sencillo programa C que establece una conexión a un servidor de base de datos MySQL */
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;mysql.h&gt;
main() {
 MYSQL *conn;
 MYSQL_RES *res;
 MYSQL_ROW row;
 char *server = &quot;localhost&quot;;
 char *user = &quot;root&quot;;
 char *password = &quot;PASSWORD&quot;; /* Poner la contraseña */
 char *database = &quot;mysql&quot;;
 conn = mysql_init(NULL);
 /* Conectarse a la base de datos */
 if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
     fprintf(stderr, &quot;%s\n&quot;, mysql_error(conn));
     exit(1);
 }
 /* enviar la consulta SQL */
 if (mysql_query(conn, &quot;show tables&quot;)) {
     fprintf(stderr, &quot;%s\n&quot;, mysql_error(conn));
     exit(1);
 }
 res = mysql_use_result(conn);
 /* imprimir los nombres de las tablas */
 printf(&quot;Tablas en la base de datos &#039;mysql&#039;:\n&quot;);
 while ((row = mysql_fetch_row(res)) != NULL) printf(&quot;%s \n&quot;, row[0]);
 /* liberar los recursos y cerrar la conexion */
 mysql_free_result(res);
 mysql_close(conn);
}</pre><p>Para compilar el programa, debemos pasar al compilador una serie de opciones que incluyen las referencias a las librerías y a los directorios en donde se encuentran los ficheros header. El paquete de desarrollo de cliente MySQL que hemos instalado incluye una utilidad «mysql_config» que genera la correspondiente lista de opciones a pasar al compilador. Haciendo uso de la misma, podemos compilar el programa de ejemplo con un comando de la forma:</p><pre class="crayon-plain-tag">$ gcc -o conexion_mysql $(mysql_config --cflags) $(mysql_config --libs) conexion_mysql.c</pre><p>Y por último, podemos comprobar el resultado ejecutando el programa:</p><pre class="crayon-plain-tag">$ ./conexion_mysql
Tablas en la base de datos &#039;mysql&#039;:
columns_priv 
db 
event 
func 
general_log 
help_category 
help_keyword 
help_relation 
help_topic 
host 
ndb_binlog_index 
plugin 
proc 
procs_priv 
proxies_priv 
servers 
slow_log 
tables_priv 
time_zone 
time_zone_leap_second 
time_zone_name 
time_zone_transition 
time_zone_transition_type 
user</pre><p></p>
<h4>Referencias:</h4>
<ul>
<li class="headline"><a href="http://www.cyberciti.biz/tips/linux-unix-connect-mysql-c-api-program.html">Howto: Connect MySQL server using C program API under Linux or UNIX</a></li>
</ul>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-conectarse-a-una-base-de-datos-mysql-desde-un-programa-c-en-linux/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo crear sobre memoria RAM un disco temporal en linux</title>
		<link>https://blog.openalfa.com/como-crear-sobre-memoria-ram-un-disco-temporal-en-linux</link>
				<comments>https://blog.openalfa.com/como-crear-sobre-memoria-ram-un-disco-temporal-en-linux#respond</comments>
				<pubDate>Thu, 05 May 2016 16:15:08 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Admon. Servidores]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7075</guid>
				<description><![CDATA[Muchas aplicaciones, como por ejemplo la popular base de datos MySQL, crean ficheros temporales en disco para la ejecución de algunos de sus procesos. El rendimiento de este tipo de aplicaciones se puede mejorar significativamente creando un disco sobre la memoria RAM del sistema, que es varios órdenes de magnitud más rápida que los discos <a href='https://blog.openalfa.com/como-crear-sobre-memoria-ram-un-disco-temporal-en-linux' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>Muchas aplicaciones, como por ejemplo la popular base de datos MySQL, crean ficheros temporales en disco para la ejecución de algunos de sus procesos. El rendimiento de este tipo de aplicaciones se puede mejorar significativamente creando un disco sobre la memoria RAM del sistema, que es varios órdenes de magnitud más rápida que los discos magnéticos convencionales, o los más recientes discos SSD.</p>
<p>En este artículo veremos cómo se puede crear un disco en RAM, y cómo configurar MySQL para que haga uso del mismo, en un sistema Debian/Ubuntu. El procedimiento se puede aplicar con ligeras modificaciones a casi todas las demás distribuciones de Linux.</p>
<p><span id="more-7075"></span></p>
<h2>1 &#8211; Determinar la cantidad de memoria física disponible</h2>
<p>Para poder utilizar un disco en memoria, el sistema debe disponer de una cantidad suficiente. El comando «free» nos indica la cantidad total de memoria disponible, y del uso que está haciendo el sistema de la misma:</p><pre class="crayon-plain-tag"># free -m
             total       used       free     shared    buffers     cached
Mem:         40323      22586      17737        816         42       1223
-/+ buffers/cache:      21320      19002
Swap:         2047         82       1965</pre><p>En este ejemplo, vemos que el sistema dispone de un total de 40323 MBytes de memoria principal (40 GBytes), de los cuales hay 17 GBytes no utilizados.</p>
<h2>2 &#8211; Crear el punto de montaje, y montar el disco RAM</h2>
<p>La configuración por defecto de un sistema Debian/Ubuntu ya incluye un filesystem tmpfs montado en «/dev/shm», que hace uso de la mitad de la memoria física disponible. Con el comando «df» podemos examinar los filesystems existentes:</p><pre class="crayon-plain-tag">$ df
Filesystem     1K-blocks      Used Available Use% Mounted on
/dev/sda2      825324976 461508928 321868864  59% /
udev               10240         0     10240   0% /dev
tmpfs            8258348    811312   7447036  10% /run
tmpfs           20645868         0  20645868   0% /dev/shm
tmpfs               5120         0      5120   0% /run/lock
tmpfs           20645868         0  20645868   0% /sys/fs/cgroup
/dev/sda1         230925     32084    182611  15% /boot
$</pre><p>En otro tipo de distribuciones Linux, en donde no exista ya un filesystem tmpfs configurado, podemos crearlo de la siguiente forma:</p>
<p>En primer lugar, creamos un directorio en el cual se va a montar el disco RAM:</p><pre class="crayon-plain-tag"># mkdir /mnt/ramdisk</pre><p>y a continuación montamos el disco con el comando:</p><pre class="crayon-plain-tag"># mount -t tmpfs -o size=10240m tmpfs /mnt/ramdisk</pre><p>Con el comando «df», podemos comprobar que el disco está creado y preparado para su uso:</p><pre class="crayon-plain-tag"># df -h /mnt/ramdisk
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            10G     0   10G   0% /mnt/ramdisk</pre><p>Opcionalmente, para que el disco se vuelva a montar cuando se reinicie el servidor, podemos añadir una línea al fichero /etc/fstab:</p><pre class="crayon-plain-tag">tmpfs       /mnt/ramdisk tmpfs   nodev,nosuid,noexec,nodiratime,size=10240M   0 0</pre><p></p>
<h2>3 &#8211; Configurar MySQL para que utilice el disco en memoria</h2>
<p>La directriz «tmpdir» en el fichero de configuración /etc/mysql/my.cnf especifica la ubicación del directorio en el cual MySQL creará las tablas temporales que necesite para la ejecución de determinadas consultas. En primer lugar, creamos un directorio «mysqltmp» bajo el directorio en el que hemos montado el disco en memoria, y le asignamos como propietario el usuario con el que se ejecuta el servicio mysql:</p><pre class="crayon-plain-tag"># mkdir /mnt/ramdisk/mysqltmp
# chown mysql:mysql /mnt/ramdisk/mysqltmp</pre><p>A continuación, editamos /etc/mysql/my.cnf para establecer dicho directorio como valor de la directriz «tmpdir»:</p><pre class="crayon-plain-tag">tmpdir          = /mnt/ramdisk/mysqltmp</pre><p>Por último reiniciamos el servicio mysql para que tenga efecto la nueva configuración:</p><pre class="crayon-plain-tag"># /etc/init.d/mysql restart</pre><p></p>
<h2>4 &#8211; Crear tablas e índices en el disco en memoria</h2>
<p>Otra posible optimización es utilizar el disco en memoria para almacenar no sólo las tablas temporales, sino las tablas permanentes.</p>
<p>Sin embargo, hay que ser consciente de que todo el contenido del disco en memoria desaparece cada vez que se reinicia el sistema, por lo que hay que establecer un procedimiento que permita recuperar esta información en el reinicio.</p>
<p>Supongamos que la base de datos contiene una tabla &#8216;mitabla&#8217;, que es accedida frecuentemente por las aplicaciones que se ejecutan en el servidor. Podemos crear en el disco en memoria una nueva tabla &#8216;mitabla_ram&#8217;, con la misma estructura que la tabla &#8216;mitabla&#8217;, y copiar a la misma el contenido de &#8216;mitabla&#8217;;</p><pre class="crayon-plain-tag">mysql&gt; CREATE table `mitabla_ram`(
           .... 
           )
           DATA DIRECTORY &#039;/mnt/shm/mysql&#039;
           INDEX DIRECTORY &#039;/mnt/shm/mysql&#039;;
mysql&gt; INSERT INTO mitabla_ram (SELECT * FROM mitabla);</pre><p>A continuación, cambiamos el nombre de las tablas para que la tabla en memoria pase a llamarse &#8216;mitabla&#8217;, y sea la tabla utilizada por la aplicación:</p><pre class="crayon-plain-tag">mysql&gt; ALTER TABLE mitabla RENAME TO mitabla_disco;
mysql&gt; ALTER TABLE mitabla_ram RENAME TO mitabla;</pre><p>Por último debemos establecer un mecanismo para:</p>
<ul>
<li>Guardar en disco el contenido de la tabla en memoria, con la periodicidad que se considere necesaria</li>
<li>En el reinicio del sistema, crear nuevamente la tabla en memoria, y cargarla con el contenido guardado en disco.</li>
</ul>
<h4>Referencias:</h4>
<ul>
<li><a href="https://www.jamescoyle.net/how-to/943-create-a-ram-disk-in-linux">Create a RAM disk in Linux</a></li>
<li><a href="http://www.kiloroot.com/create-a-ram-disk-in-linux-tell-mysql-to-put-stuff-there/">Create a RAM Disk in Linux &amp; Use It to Speed Up MySQL…</a></li>
</ul>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-crear-sobre-memoria-ram-un-disco-temporal-en-linux/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo añadir un fichero de swap a un sistema Linux</title>
		<link>https://blog.openalfa.com/como-anadir-un-fichero-de-swap-a-un-sistema-linux</link>
				<comments>https://blog.openalfa.com/como-anadir-un-fichero-de-swap-a-un-sistema-linux#respond</comments>
				<pubDate>Sun, 01 May 2016 12:08:13 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Admon. Servidores]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7064</guid>
				<description><![CDATA[En momentos de mucho uso, un servidor puede necesitar puntualmente ejecutar simultáneamente un número elevado de procesos. Cada proceso necesita reservar una cantidad de memoria física, y en ocasiones puede no haber suficiente memoria disponible para todos. En este caso, el sistema rechaza la ejecución de los nuevos procesos. Para evitar esto, se puede configurar <a href='https://blog.openalfa.com/como-anadir-un-fichero-de-swap-a-un-sistema-linux' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>En momentos de mucho uso, un servidor puede necesitar puntualmente ejecutar simultáneamente un número elevado de procesos. Cada proceso necesita reservar una cantidad de memoria física, y en ocasiones puede no haber suficiente memoria disponible para todos.</p>
<p>En este caso, el sistema rechaza la ejecución de los nuevos procesos.</p>
<p>Para evitar esto, se puede configurar un espacio de swap en disco. De este modo, el sistema guarda temporalmente en dicho espacio los bloques de memoria que tienen menos accesos, para liberar espacio y permitir la ejecución de los nuevos procesos.</p>
<p>En un servidor dedicado, es habitual crear una partición de disco dedicada a swap. Pero en otros casos no es posible particionar el disco. Este es en muchas ocasiones el caso de una máquina virtual contratada a un proveedor de hosting (Amazon Web Services, DigitalOcean, &#8230;)</p>
<p>En este caso, es posible crear un fichero y configurar el sistema para que lo utilize como espacio de swap. En este artículo se explica cómo realizar una configuración de este tipo.</p>
<p><span id="more-7064"></span></p>
<h2>1. Crear el fichero de swap</h2>
<p>En este paso vamos a crear un fichero dedicado a swap bajo el directorio «/var». Por seguridad, establecemos los permisos de manera que sólo el usuario root pueda leer y escribir en el mismo. Como usuario root, ejecutamos:</p><pre class="crayon-plain-tag"># cd /var
# touch swap.img
# chmod 600 swap.img</pre><p></p>
<h2>2. Dar un tamaño al fichero de swap</h2>
<p>Lo habitual es dar al fichero un tamaño entre una y dos veces la cantidad de memoria física disponible en el sistema. En el siguiente ejemplo, crearemos un fichero con 2048 bloques de 1024k cada uno, para obtener un total de 2 GBytes. Como usuario root:</p><pre class="crayon-plain-tag"># dd if=/dev/zero of=/var/swap.img bs=1024k count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 4.0868896 s, 253 MB/s
#</pre><p></p>
<h2>3. Inicializar el fichero en forma de swap filesystem</h2>
<p>El comando mkswap realiza un formateo del fichero, que lo prepara para ser utilizado como espacio de swap</p><pre class="crayon-plain-tag"># mkswap /var/swap.img
Setting up swapspace version 1, size = 1020 GiB
no label, UUID=72761533-8xbe-436l-b07e-c0sabe9cedf3</pre><p></p>
<h2>4. Habilitar el fichero de swap para ser usado por el sistema</h2>
<p>Finalmente, con el comando swapon indicamos al sistema que utilice el fichero creado como espacio de swap</p><pre class="crayon-plain-tag"># swapon /var/swap.img</pre><p>De la misma forma, podemos utilizar el comando &#8216;swapoff&#8217; si en algún momento queremos dejar de usar el fichero como espacio de swap.</p>
<h2>5. Configurar el sistema para que monte el fichero de swap durante el reinicio</h2>
<p>La manera más sencilla de indicar al sistema que monte el fichero como swap durante el reinicio es añadir una entrada al fichero de configuración &#8216;/etc/fstab&#8217;, como en el siguiente ejemplo:</p><pre class="crayon-plain-tag"># echo &quot;/var/swap.img    none    swap    sw    0    0&quot; &gt;&gt; /etc/fstab</pre><p>Nota: El espacio de swap sólo es útil si el sistema dispone habitualmente de suficiente memoria física para atender la carga de proceso que recibe, y sólo esporádicamente sufre picos de carga que durante breves momentos requieren más memoria de la que hay disponible. En caso contrario, el sistema estará continuamente leyendo y escribiendo del disco los bloques de memoria física que necesita (en lo que se conoce como «trashing»), y el rendimiento del sistema se degradará hasta el punto de inutilizarlo en la práctica.</p>
<h4>Referencias:</h4>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-configure-virtual-memory-swap-file-on-a-vps">How to configure Virtual Memory (Swap File) on a VPS</a></li>
</ul>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-anadir-un-fichero-de-swap-a-un-sistema-linux/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Cómo crear túneles ssh</title>
		<link>https://blog.openalfa.com/como-crear-tuneles-ssh</link>
				<comments>https://blog.openalfa.com/como-crear-tuneles-ssh#comments</comments>
				<pubDate>Fri, 29 Apr 2016 07:11:41 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Admon. Servidores]]></category>

		<guid isPermaLink="false">http://blog.openalfa.com/?p=7053</guid>
				<description><![CDATA[La comunicación a través de internet entre una máquina cliente y un servidor supone un problema de seguridad. Normalmente, para ofrecer un determinado servicio, el servidor abre un puerto TCP en su dirección IP pública, y queda a la espera de solicitudes de conexión del cliente. Esto deja al servidor expuesto a ataques procedentes de <a href='https://blog.openalfa.com/como-crear-tuneles-ssh' class='excerpt-more'>[...]</a>]]></description>
								<content:encoded><![CDATA[<p>La comunicación a través de internet entre una máquina cliente y un servidor supone un problema de seguridad. Normalmente, para ofrecer un determinado servicio, el servidor abre un puerto TCP en su dirección IP pública, y queda a la espera de solicitudes de conexión del cliente. Esto deja al servidor expuesto a ataques procedentes de cualquier otra máquina conectada a internet.</p>
<p>En este artículo se explica una de las posibles soluciones a este problema, mediante la creación de túneles de comunicación SSH.</p>
<p><span id="more-7053"></span></p>
<p>Utilizando un túnel SSH, se puede configurar el servidor para que sólo abra en su dirección local (localhost, 127.0.0.1) el puerto TCP correspondiente al servicio que ofrece. El cliente se conectará a su vez a un puerto local (el número de puerto puede ser distinto del número de puerto en el que escucha el servidor). El túnel se encarga de encriptar toda la información enviada por el cliente, y enviarla al puerto local del servidor. De la misma forma, el túnel lee toda la la información que escribe el servidor en su puerto local, la encripta y la envía al puerto local en el que lee el cliente.</p>
<p>Vamos a tomar como ejemplo una máquina cliente «cliente» que necesita conectarse a una base de datos MySQL que reside en un servidor «ejemplo.com». Si no se usa un túnel, el servidor debe permitir el establecimiento de conexiones en su dirección pública <strong>ejemplo.com:3306</strong>.</p>
<h2>Redirección de puerto local (local port forwarding)</h2>
<p>En primer lugar, configuramos el servidor para que sólo permita conexiones locales a la dirección localhost:3306.</p>
<p>A continuación, iniciamos una sesión ssh desde el cliente al servidor, en la que solicitamos la creación de un túnel entre el puerto 5000 del cliente al puerto 3306 del servidor, con el siguiente comando:</p><pre class="crayon-plain-tag">$ ssh -L 5000:localhost:3306 usuario@ejemplo.com</pre><p>Una vez establecida la sesión, desde otro terminal del cliente podemos conectarnos a la base de datos del servidor con el comando:</p><pre class="crayon-plain-tag">$ mysql -h 127.0.0.1 -P 5000</pre><p>Los datos que escribe el cliente en el puerto 5000 de su dirección local, son encriptados y enviados por el túnel al puerto 3306 del servidor, y los datos que devuelve el servidor son también encriptados, y enviados al cliente a través del túnel.</p>
<p>Como vemos en este ejemplo, para crear el túnel hemos tenido que establecer primero una sesión interactiva ssh, y después conectarnos desde otro terminal a la base de datos. Para evitar esto se pueden utilizar los flags «-nNT», de manera que el comando ssh no establezca la sesión interactiva, y simplemente realice la redirección de puertos:</p><pre class="crayon-plain-tag">$ ssh -nNT -L 5000:localhost:3306 usuario@ejemplo.com</pre><p></p>
<h2>Creación de túneles persistentes</h2>
<p>El túnel ssh creado en el apartado anterior sólo permanece mientras está establecida la sesión ssh en la que se estableció.</p>
<p>Para poder crear un túnel persistente, que no dependa de una sesión interactiva, podemos utilizar el comando «autossh». autossh se encarga de establecer una sesión ssh en background, y comprueba periódicamente que la sesión permanezca activa. Si por cualquier razon (problema de red o de otro tipo) la sesión ssh finaliza, autossh se encarga de establecer una nueva sesión.</p>
<p>Para crear el túnel con autossh, utilizamos el comando:</p><pre class="crayon-plain-tag">$ /usr/lib/autossh/autossh -f -N -L 5000:localhost:3306 usuario@ejemplo.com</pre><p></p>
<h2>Script de creación de túneles ssh en el reinicio</h2>
<p>Para que se creen los túneles ssh durante el renicio del servidor, debemos crear un script «/etc/init.d/autossh», como el script de ejemplo que se puede descargar pulsando <a href="/wp-content/uploads/sites/2/2016/05/autossh.gz">aqui</a>.</p>
<p>Este script puede crear múltiples túneles a distintos servidores. La configuración de túneles para cada uno de los servidores se guarda en un fichero «/etc/autossh/&lt;server&gt;». Por ejemplo:</p><pre class="crayon-plain-tag"># cat /etc/autossh/server1 
# Comprueba la conexión cada 10 segundos.
# Tras 3 intentos fallidos, cierra la conexión y la vuelve a establecer
ServerAliveInterval=&quot;10&quot;
ServerAliveCountMax=&quot;3&quot;
StrictHostKeyChecking=&quot;no&quot;
 
LocalUser=&quot;root&quot;
IdentityFile=&quot;~/.ssh/id_rsa&quot;
 
RemoteUser=&quot;usuario&quot;
RemoteHost=&quot;server1&quot;
RemotePort=&quot;22&quot;
 
# Lista de túneles locales y remotos a establecer
# 
# En este ejemplo:
#    - conecta el puerto remoto 10550 con el puerto local 10050
#    - conecta el puerto local 10051 con el puerto remoto 10051
ForwardPort=(
    &quot;R 127.0.0.1:10550:localhost:10050&quot;
    &quot;L 127.0.0.1:10051:localhost:10051&quot;
)</pre><p></p>
<h2>Redirección de puerto remoto (Remote port forwarding)</h2>
<p>Un caso similar que también se puede solucionar mediante un túnel ssh se da cuando desde un máquina cliente conectada a internet queremos acceder a un servicio ofrecido por un servidor «server1» que no tiene conexión directa a internet.</p>
<p>En este caso, podemos utilizar un segundo servidor «server2.com» que sí está conectado a internet, para establecer la comunicación:</p>
<ul>
<li>Desde el servidor «server1», extablecemos una sesión ssh en la que creamos un túnel remoto:<br />
<pre class="crayon-plain-tag">ssh -R 5000:localhost:3306 usuario@server2.com</pre><br />
Como se puede ver, en este caso utilizamos la opción «-R» para establecer un túnel remoto, en lugar de la opción «-L» que establecer un túnel local. Con este comando, el servidor «server2.com» queda a la espera de conexiones en el puerto 9000, y transmite la información que reciba al puerto 3306 del servidor «server1».</li>
<li>Una vez establecido el túnel, desde el cliente podemos establecer una sesión interactiva al servidor «server2.com», y desde allí conectarnos a la base de datos MySQL del servidor «server1»:<br />
<pre class="crayon-plain-tag">cliente$ ssh usuario@server2.com
  ...
server2$ mysql -h 127.0.0.1 -P 5000</pre>
</li>
</ul>
<h4>Referencias:</h4>
<p><a href="http://blog.trackets.com/2014/05/17/ssh-tunnel-local-and-remote-port-forwarding-explained-with-examples.html">SSH Tunnel &#8211; Local and Remote Port Forwarding Explained With Examples</a></p>
<p>&#8212;</p>
]]></content:encoded>
							<wfw:commentRss>https://blog.openalfa.com/como-crear-tuneles-ssh/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
							</item>
	</channel>
</rss>
