<?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>Petryx :: &#187; Tutoriais</title>
	<atom:link href="http://petryx.blogrs.com.br/category/tutoriais/feed/" rel="self" type="application/rss+xml" />
	<link>http://petryx.blogrs.com.br</link>
	<description>Linux,Java,Postgresql,Banco de dados, Processamento de imagens</description>
	<lastBuildDate>Fri, 30 Jul 2010 11:11:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>PL/PGSQL Funções Aninhadas</title>
		<link>http://petryx.blogrs.com.br/2008/10/29/plpgsql-funcoes-aninhadas/</link>
		<comments>http://petryx.blogrs.com.br/2008/10/29/plpgsql-funcoes-aninhadas/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 00:22:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[pl/pgsql]]></category>
		<category><![CDATA[postgresql]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=119</guid>
		<description><![CDATA[Utilizando a versão 8.2.7 do Postgresql verifiquei a possibilidade de criar funções aninhadas. Veja o exemplo: CREATE OR REPLACE FUNCTION testNestedFunction() RETURNS REAL as $$ DECLARE v_test REAL; r REAL; BEGIN CREATE OR REPLACE FUNCTION addTest(a REAL,b REAL) RETURNS REAL AS $BODY_ADDTEST$ DECLARE r REAL; BEGIN r := a + b; RETURN r; END; $BODY_ADDTEST$language [...]]]></description>
			<content:encoded><![CDATA[<p>Utilizando a versão 8.2.7 do Postgresql verifiquei a possibilidade de criar funções aninhadas.<br />
Veja o exemplo:</p>
<pre name='code' class='sql'>
CREATE OR REPLACE FUNCTION testNestedFunction() RETURNS  REAL as
$$
<<global>>
DECLARE
v_test REAL;
r REAL;
BEGIN
   CREATE OR REPLACE FUNCTION addTest(a REAL,b REAL) RETURNS REAL AS
   $BODY_ADDTEST$
	DECLARE
		r REAL;
	BEGIN
		r := a + b;
	RETURN r;
   END;
   $BODY_ADDTEST$language plpgsql;

   r := addTest(1,1);
   RAISE NOTICE 'addTest = %',r;

   r := addTest(2,2);
   RAISE NOTICE 'addTest = %',r;

   RETURN r;
END global;
$$ LANGUAGE 'plpgsql';
</pre>
<p>Na função acima criei uma função aninhada chamada <strong>addTest(REAL,REAL)</strong> recebendo como parâmetro dois valores do tipo real, com os quais é efetuado uma soma e retornado o resultado. Executando a função temos o seguinte resultado:</p>
<pre name='code' class='sql'>
SELECT testNestedFunction();

NOTA:  addTest = 2
NOTA:  addTest = 4

Tempo total de execução da consulta: 18 ms.
1 registros recuperados.
</pre>
<p>Como pode ser visto foi realizado duas chamadas a função aninhada <strong>addTest()</strong> passando diferentes parâmetros.</p>
<p>O interessante é que o Postgresql cria duas funções: <strong>testNestedFunction()</strong> e <strong>addTest(REAL,REAL)</strong>. E não somente uma função aninhada, isso favorece aos bugs, vamos simular um então.</p>
<p>Vamos deletar a função <strong>addTest(REAL,REAL)</strong> e executar novamente.</p>
<pre name='code' class='sql'>
DROP FUNCTION addtest(real, real);
SELECT testNestedFunction();

ERRO:  cache lookup failed for function 1906343
CONTEXT:  PL/pgSQL function "testnestedfunction" line 16 at assignment

********** Erro **********

ERRO: cache lookup failed for function 1906343
SQL state: XX000
Contexto: PL/pgSQL function "testnestedfunction" line 16 at assignment
</pre>
<p>O comando <strong>DROP FUNCTION addTest(REAL,REAL)</strong> não verificou que a função <strong>testnestedfunction() </strong> é depende daquela para sua execução, procurei na documentação uma maneira de declarar a dependência mas não encontrei. Outro detalhe interessante é que a função <strong>addTest()</strong> não existe até a primeira execução, ou seja, quando o comando é executado <strong>SELECT testnestedfunction()</strong> pela primeira vez a função <strong>addTest() </strong>é criada. Então quando deletamos a função <strong>addTest()</strong> e executamos novamente o comando <strong>SELECT testnestedfunction()</strong>, a função <strong>addTest()</strong> não é criada novamente. </p>
<p>Funções aninhadas são interessantes para melhorar a leitura do código e prover reutilização de código. O problema é se por acidente algum DBA deletar a função aninhada como mostrado acima. Irá causar um bug difícil de resolver. Pois, a resposta do erro é pouco intuitiva não informando claramente a função que não foi encontrada.</p>
<p>Criar funções separadas é uma outra solução invés de criar uma função aninhada. Mas, o problema que dificulta a leitura e entendimento do código.</p>
<p>Carpe Diem!</p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/10/29/plpgsql-funcoes-aninhadas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PL/PGSQL blocos de código</title>
		<link>http://petryx.blogrs.com.br/2008/10/29/plpgsql-blocos-de-codigo/</link>
		<comments>http://petryx.blogrs.com.br/2008/10/29/plpgsql-blocos-de-codigo/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 20:08:07 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[pl/pgsql]]></category>
		<category><![CDATA[postgresql]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=118</guid>
		<description><![CDATA[A linguagem PL/PGSQL permite a criação de blocos de código. Com essa característica é possível definir o escopo das variáveis. Sendo um recurso interessante para deixar o código mais legível, auxiliando também na depuração do código. As variáveis existem no momento da declaração do bloco até o final do bloco onde a variável é declarada. [...]]]></description>
			<content:encoded><![CDATA[<p>A linguagem PL/PGSQL permite a criação de blocos de código. Com essa característica é possível definir o escopo das variáveis. Sendo um recurso interessante para deixar o código mais legível, auxiliando também na depuração do código.<br />
As variáveis existem no momento da declaração do bloco até o final do bloco onde a variável é declarada.<br />
Rótulos podem ser adicionados aos blocos para melhorar a leitura e também para qualificar as variáveis que existem dentro do bloco. Os blocos de código são definidos da seguinte forma: </p>
<pre name="code" class="sql">
<<label>>
DECLARE
        declarations
BEGIN
       statements
END;
</pre>
<p>Como exemplo vamos criar uma função onde teremos dois blocos global e local, com uma variável declarada no bloco global com o nome v_test do tipo real e outra variável também declarada com o nome v_test dentro do bloco local. Veja o exemplo:</p>
<pre name="code" class="sql">
CREATE OR REPLACE FUNCTION test() RETURNS VOID as
$$
<<global>>
DECLARE
v_test REAL;
BEGIN
        v_test := 1;
        <<local>>
        DECLARE
             v_test REAL;
        BEGIN
	      v_test :=2;
	      RAISE NOTICE 'global.v_test = %, v_test = %',global.v_test,v_test;
        END local;

 RAISE NOTICE 'Global v_test = %',v_test;

END global;
$$ LANGUAGE 'plpgsql';
</pre>
<p>Resultado da execução:</p>
<pre name="code" class="sql">
select test();
NOTA:  global.v_test = 1, v_test = 2
NOTA:  Global v_test = 1
Tempo total de execução da consulta: 6 ms.
1 registros recuperados.
</pre>
<p>Essa função demonstra claramente o escopo da variáveis e também demonstra que podemos ter sub blocos de código dentro de uma função.<br />
É importante notar que BEGIN/END é utilizado para agrupar as declarações da linguagem PL/PGSQL e também como comandos de controle de transações. Mas, um detalhe interessante é que funções e triggers não podem iniciar ou encerrar transações e o Postgresql não suporta transações aninhadas.</p>
<p>Carpe Diem. </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/10/29/plpgsql-blocos-de-codigo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java Comunicando com equipamentos Modbus</title>
		<link>http://petryx.blogrs.com.br/2008/08/15/java-comunicando-com-equipamentos-modbus/</link>
		<comments>http://petryx.blogrs.com.br/2008/08/15/java-comunicando-com-equipamentos-modbus/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 03:56:45 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=94</guid>
		<description><![CDATA[Participei de vários projetos de automação industrial onde era necessário ler ou escrever instrumentos como medidores de temperatura, medidores de energia elétrica e outros equipamentos que implementam o protocolo Modbus RTU. A linguagem Java possui uma API muito boa para comunicar com instrumentos que utilizam o protocolo Modbus RTU a API Jamod. Além de propiciar [...]]]></description>
			<content:encoded><![CDATA[<p>Participei de vários projetos de automação industrial onde era necessário ler ou escrever  instrumentos como medidores de temperatura, medidores de energia elétrica e outros equipamentos que implementam o protocolo Modbus RTU.</p>
<p>A linguagem Java possui uma API muito boa para comunicar com instrumentos que utilizam o protocolo Modbus RTU a API <a href="http://jamod.sourceforge.net/">Jamod</a>. Além de propiciar a comunicação com equipamentos e instrumentos função do Master da rede, também é possível fazer com a aplicação ser torne um Slave Modbus, respondendo as solicitações do Master. </p>
<p>A documentação da Api Jamod é boa, possui vários códigos de exemplo para implementar ModBus Escravo e Modbus Mestre.</p>
<p>Entendo o protocolo ModBus <a href="http://jamod.sourceforge.net/kbase/protocol.html">http://jamod.sourceforge.net/kbase/protocol.html</a></p>
<p>How-To&#8217;s de como utilizar o Jamod <a href="http://jamod.sourceforge.net/kbase/modbus_udp.html">http://jamod.sourceforge.net/kbase/modbus_udp.html</a></p>
<p>Thats all Folks <img src='http://petryx.blogrs.com.br/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/08/15/java-comunicando-com-equipamentos-modbus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PL/PGSQL Programando no Postgresql</title>
		<link>http://petryx.blogrs.com.br/2008/07/13/plpgsql-programando-no-postgresql/</link>
		<comments>http://petryx.blogrs.com.br/2008/07/13/plpgsql-programando-no-postgresql/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 00:41:03 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[pl/pgsql]]></category>
		<category><![CDATA[postgresql]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=77</guid>
		<description><![CDATA[Postgresql suporta uma variedade de linguagens procedurais, podemos programar uma store procedure na linguagens de nossa preferência como exemplos: Pl/Perl, Pl/Python, Pl/Java, Pl/PHP, Pl/Ruby e muitas outras. Para utilizar estas linguagens primeiro é necessário habilitar na base de dados. O comando para habilitar a linguagem na base de dados não é complicado. Nesse post iremos [...]]]></description>
			<content:encoded><![CDATA[<p>Postgresql suporta uma variedade de linguagens procedurais, podemos programar uma store procedure na linguagens de nossa preferência como exemplos: Pl/Perl, Pl/Python, Pl/Java, Pl/PHP, Pl/Ruby e muitas outras. Para utilizar estas linguagens primeiro é necessário habilitar na base de dados.</p>
<p>O comando para habilitar a linguagem na base de dados não é complicado. Nesse post iremos utilizar a linguagem nativa do PostgreSQL que PL/PGSQL. </p>
<p>Habilitando a linguagem em uma bases de dados. </p>
<p><strong>create lang plpgsql nomedabasededados</strong></p>
<p>Por exemplo na base de dados book</p>
<p><strong>create lang plpgsql book</strong></p>
<p>Este comando deve ser executado no shell.</p>
<p>O exemplo tem a finalidade de mostrar o poder de um procedimento armazenado (store procedure) da linguagem PL/PGSQL está linguagem somente irá atuar dentro da base de dados, então não será possível executar comandos externos. Caso seja necessário é possível desenvolver uma função externa em C ou usar uma linguagem procedural não confiável a qual pode inserir algum risco de segurança a base de dados.</p>
<p>Voltando ao exemplo vamos desenvolver o algoritmo da torre de hanoi em PL/PGSQL. </p>
<pre name='code' class='sql'>
CREATE FUNCTION towerHanoi(ndisk INTEGER,src INTEGER,dst INTEGER, tmp INTEGER) RETURNS void AS '
Declare

BEGIN
	IF ndisk = 1 THEN
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,dst;
	ELSE
		perform towerHanoi(ndisk - 1,src,dst,tmp);
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,tmp;
		perform towerHanoi(ndisk - 1,src,tmp,src);
	END IF;

END;
' LANGUAGE 'plpgsql';
</pre>
<p>Executando a função<br />
<strong>select towerHanoi(3,1,2,3);</strong></p>
<p>Veja o resultado da função</p>
<p><strong>NOTA:   DISK 1 Move da haste 1 para haste 2<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $4 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 7 at perform<br />
comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $4 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 7 at perform<br />
<strong>NOTA:   DISK 2 Move da haste 1 para haste 3<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $4 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 7 at perform<br />
<strong>NOTA:   DISK 1 Move da haste 1 para haste 3<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $2 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 9 at perform<br />
comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $4 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 7 at perform<br />
<strong>NOTA:   DISK 3 Move da haste 1 para haste 3<br />
NOTA:   DISK 1 Move da haste 1 para haste 3<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $4 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 7 at perform<br />
comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $2 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 9 at perform<br />
<strong>NOTA:   DISK 2 Move da haste 1 para haste 1<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $2 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 9 at perform<br />
<strong>NOTA:   DISK 1 Move da haste 1 para haste 1<br />
</strong>CONTEXT:  comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $2 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 9 at perform<br />
comando SQL &#8220;SELECT  towerHanoi( $1  &#8211; 1, $2 , $3 , $2 )&#8221;<br />
PL/pgSQL function &#8220;towerhanoi&#8221; line 9 at perform</p>
<p>Total query runtime: 2 ms.<br />
Data retrieval runtime: 7 ms.<br />
1 rows retrieved.</p>
<p>Esta simples função demonstra como usar recursividade, passagem de parâmetros e como chamar uma função em PL/PGSQL. </p>
<p>Estou pesquisando pra ver se consigo fazer uma árvore binária em PL/PGSQL. Quando eu conseguir coloco o algoritmo.</p>
<p>Abraços</p>
<p>Hei pessoal não se esqueçam a assinatura dos feeds é gratuita então não percam tempo.<br /></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/07/13/plpgsql-programando-no-postgresql/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Explorando o PostgreSQL &#8211; Como descobrir o tamanho de uma tabela no disco</title>
		<link>http://petryx.blogrs.com.br/2008/07/12/explorando-o-postgresql-como-descobrir-o-tamanho-de-uma-tabela-no-disco/</link>
		<comments>http://petryx.blogrs.com.br/2008/07/12/explorando-o-postgresql-como-descobrir-o-tamanho-de-uma-tabela-no-disco/#comments</comments>
		<pubDate>Sat, 12 Jul 2008 03:00:30 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[postgresql]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=75</guid>
		<description><![CDATA[A algum tempo atrás, surgiu a necessidade de saber o tamanho de cada tabela em bytes, numa base de dados (database) Postgresql. Era necessário para estimar o crescimento destas tabelas e saber quanto tempo levaria que esgotar a capacidade do HD. Nesta pesquisa encontrei muitos dados interessantes que irei compartilhar com vocês. Claro que para [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://petryx.blogrs.com.br/wp-content/uploads/2008/07/postgresql.jpeg'><img src="http://petryx.blogrs.com.br/wp-content/uploads/2008/07/postgresql.jpeg" alt="imagem postgresql" title="postgresql" width="143" height="147" class="alignleft size-medium wp-image-76" /></a>A algum tempo atrás, surgiu a necessidade de saber o tamanho de cada tabela em bytes, numa base de dados (database) Postgresql. Era necessário para estimar o crescimento destas tabelas e saber quanto tempo levaria que esgotar a capacidade do HD.<br />
Nesta pesquisa encontrei muitos dados interessantes que irei compartilhar com vocês. Claro que para alguns não terá novidade nenhuma nesta matéria, mas com certeza será valioso para alguém como foi para mim.</p>
<p>Antes de começar temos que entender como o postgresql gerencia os arquivos da base de dados, então vamos explora-lo.</p>
<p><strong>Como PostgreSQL gerencia os arquivos da base de dados ?</strong></p>
<p>O conceito fundamental do Postgresql e de outros SGBDS é que os dados são armazenados em tabelas e as tabelas agrupadas em base de dados (databases). Em um nível mais alto desta organização as base de dados são agrupadas em clusters – e um cluster de base de dados é gerenciado pelo <strong>postmaster</strong>.<br />
<strong><br />
E como fica essa hierarquia no disco ?<br />
</strong><br />
Para descobrir como funciona essa hierarquia na prática vamos fazer umas consultas (queries) , executar um comandos no shell.<br />
Vamos começar conectando a base de dados e descobrindo o OID (Obect ID) através de uma consulta.</p>
<p>~$ psql book -U postgres</p>
<p>book=# SELECT datname, oid from pg_database;</p>
<table >
<tr>
<th align="center">datname</th>
<th align="center">oid</th>
</tr>
<tr valign="top">
<td align="left">postgres</td>
<td align="right">10819</td>
</tr>
<tr valign="top">
<td align="left">book</td>
<td align="right">16384</td>
</tr>
<tr valign="top">
<td align="left">template1</td>
<td align="right">1</td>
</tr>
<tr valign="top">
<td align="left">template0</td>
<td align="right">10818</td>
</tr>
</table>
<p>(4 registros)
</p>
<p>Na resposta da nossa query podemos ver que temos 4 base de dados (databases) no cluster. Agora podemos encontrar as base de dados no disco dentro do diretório $PG_DATA.</p>
<p>~$ cd $PG_DATA<br />
~$ ls<br />
base    pg_clog      pg_ident.conf  pg_subtrans  pg_twophase  pg_xlog postmaster.opts<br />
global  pg_hba.conf  pg_multixact   pg_tblspc    PG_VERSION   postgresql.conf  postmaster.pid</p>
<p>Dentro do subdiretório base encontra-se as base de dados no SELECT que executamos antes tem um oid 1 para a base de dados (datname) template1. Vamos entrar dentro do diretório base e ver o que tem por lá.<br />
~$ cd base<br />
~$ ls -la<br />
drwx&#8212;&#8212;  2 postgres postgres 2648 Jul 11 11:17 1<br />
drwx&#8212;&#8212;  2 postgres postgres 2648 Jul 11 11:17 10818<br />
drwx&#8212;&#8212;  2 postgres postgres 2680 Jul 11 11:18 10819<br />
drwx&#8212;&#8212;  2 postgres postgres 2680 Jul 11 11:39 16384</p>
<p>Neste exemplo temos 4 diretórios o mesmo números de registros quando executamos o SELECT então isso demonstra que o OID(object ID) corresponde ao nome do diretorio dentro da base de dados. Como exemplo o diretórios  1 corresponde a base de dados template1.<br />
Entrando no diretório 1 podemos ver que existem vários arquivos vamos descobrir  o que significa cada um deles.</p>
<p>~$ cd 1<br />
~$ ls<br />
10737  10747  10757  10767  1250  2603  2609  2615  2650  2656  2662  2668  2678  2684 690  2700  2831  2837 10739  10749  10759  10769  1255  2604  2610  2616  2651  2657  2663  2669<br />
&#8230;.<br />
&#8230;.</p>
<p>Para saber o que significa cada um desses arquivos temos que descobrir os OIDS dentro da base de dados template1. Vamos voltar ao psql</p>
<p>~$ psql -q -d template1<br />
template1=# select oid, relname from pg_class;</p>
<table>
<tr>
<th align="center">oid</th>
<th align="center">relname</th>
</tr>
<tr valign="top">
<td align="right">10762</td>
<td align="left">sql_sizing</td>
</tr>
<tr valign="top">
<td align="right">10769</td>
<td align="left">pg_toast_10767</td>
</tr>
<tr valign="top">
<td align="right">10771</td>
<td align="left">pg_toast_10767_index</td>
</tr>
<tr valign="top">
<td align="right">10767</td>
<td align="left">sql_sizing_profiles</td>
</tr>
<tr valign="top">
<td align="right">10772</td>
<td align="left">table_constraints</td>
</tr>
<tr valign="top">
<td align="right">10776</td>
<td align="left">table_privileges</td>
</tr>
<tr valign="top">
<td align="right">10780</td>
<td align="left">tables</td>
</tr>
<tr valign="top">
<td align="right">10784</td>
<td align="left">triggered_update_columns</td>
</tr>
<tr valign="top">
<td align="right">10787</td>
<td align="left">triggers</td>
</tr>
</table>
<p>Na tabela pg_class existe mais informação que pode nos ajudar a explorar a estrutura de armazenamento do PostgreSQL.</p>
<p>psql book -Upostgres<br />
book=# select relname,oid,relpages, reltuples FROM pg_class ORDER BY OID;</p>
<table>
<tr valign="top">
<tr>
<th align="center">relname</th>
<th align="center">oid</th>
<th align="center">relpages</th>
<th align="center">reltuples</th>
</tr>
<td align="left">pg_type</td>
<td align="right">1247</td>
<td align="right">5</td>
<td align="right">242</td>
</tr>
<tr valign="top">
<td align="left">pg_autovacuum</td>
<td align="right">1248</td>
<td align="right">0</td>
<td align="right">0</td>
</tr>
<tr valign="top">
<td align="left">pg_attribute</td>
<td align="right">1249</td>
<td align="right">28</td>
<td align="right">1628</td>
</tr>
<tr valign="top">
<td align="left">pg_autovacuum_vacrelid_index</td>
<td align="right">1250</td>
<td align="right">1</td>
<td align="right">0</td>
</tr>
<tr valign="top">
<td align="left">pg_proc</td>
<td align="right">1255</td>
<td align="right">45</td>
<td align="right">1929</td>
</tr>
<tr valign="top">
<td align="left">pg_class</td>
<td align="right">1259</td>
<td align="right">5</td>
<td align="right">204</td>
</tr>
</table>
<p>A coluna <strong>reltuples</strong> informa quantas tuplas tem em cada tabela. Já a coluna <strong>relpages</strong> mostra quantas páginas (pages) são requiridas para armazenar o conteúdo da tabela.</p>
<p><strong>Qual a correspondência entre relpages e reltuples com o tamanho do arquivo no disco ?<br />
</strong></p>
<p>Vamos listar o conteúdo do diretório e pegar dois exemplos</p>
<pre class="sh">$ ls -l 1247 1249
-rw------- 1 postgres postgres  40960 Jul  11 11:17 1247
-rw------- 1 postgres postgres 229376 Jul 11 11:17 1249
</pre>
<p>O arquivo chamado <strong>1247</strong> tabela pg_type ocupa um espaço em disco e <strong>40960 bytes</strong>. Se dividirmos <strong>40960/5 relpages  = 8192 bytes</strong>, realizando o mesmo cálculo para a tabela  pg_attribute que corresponde ao arquivo 1249 que possui um tamanho em disco de <strong>229376 bytes / 28 relpages = 8192 bytes</strong>.<br />
O tamanho 8192 refere-se ao tamanho da página este valor é fixo como podemos verificar.</p>
<p>Com esta matéria  acho que consegui mostrar como o PostgreSQL estrutura os dados no disco.<br />
E como descobrir o tamanho da tabela no Hd, com certeza existe outras maneiras mas escolhi está para demonstrar também como o postgresql organiza as tabelas no HD. </p>
<p>Referência:<br />
Livro PostgreSQL &#8211; Korry Douglas e Susan Douglas </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/07/12/explorando-o-postgresql-como-descobrir-o-tamanho-de-uma-tabela-no-disco/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Transferindo dados com segurança</title>
		<link>http://petryx.blogrs.com.br/2008/07/09/transferindo-dados-com-seguranca/</link>
		<comments>http://petryx.blogrs.com.br/2008/07/09/transferindo-dados-com-seguranca/#comments</comments>
		<pubDate>Thu, 10 Jul 2008 00:51:00 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Dicas Linux]]></category>
		<category><![CDATA[Segurança]]></category>
		<category><![CDATA[Tutoriais]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=72</guid>
		<description><![CDATA[Segurança na troca de mensagens e arquivos está se tornando cada vez mais necessário para manter nossa privacidade ou algum projeto confidencial. Encontrei um tutorial em vídeo no linux journal o tutorial é em inglês mas é possível seguir os passos e aprender a usar o GnuPG e PGP. Muito bom vale a pena assistir. [...]]]></description>
			<content:encoded><![CDATA[<p>Segurança na troca de mensagens e arquivos está se tornando cada vez mais necessário para manter nossa privacidade ou algum projeto confidencial. Encontrei um tutorial em vídeo no <a href="http://www.linuxjournal.com/video/linux-howto-secure-your-data-pgp">linux journal</a> o tutorial é em inglês mas é possível seguir os passos e aprender a usar o GnuPG e PGP.</p>
<p><strong>Muito bom vale a pena assistir.<br />
Parte 1</strong><br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/0CcW-kXUz3o&#038;hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/0CcW-kXUz3o&#038;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object></p>
<p>Parte 2</p>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bQYwqzS-Wyo&#038;hl=en"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/bQYwqzS-Wyo&#038;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object></p>
<p></p>
<p>Pessoal assinem os feed do blog é de graça. </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/07/09/transferindo-dados-com-seguranca/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Gerenciando pacotes no Gentoo</title>
		<link>http://petryx.blogrs.com.br/2008/07/03/gerenciando-pacotes-no-gentoo/</link>
		<comments>http://petryx.blogrs.com.br/2008/07/03/gerenciando-pacotes-no-gentoo/#comments</comments>
		<pubDate>Fri, 04 Jul 2008 02:57:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Dicas Linux]]></category>
		<category><![CDATA[Tutoriais]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=64</guid>
		<description><![CDATA[O gentoo possui um ótimo gerenciador de pacotes, diga-se de passagem foi um dos 5 motivos que me fez usa-lo. A idéia deste post é mostrar como gerenciar os pacotes instalados de forma simples. Para gerenciar os pacotes os desenvolvedores do gentoo fizeram uma excelente ferramenta a Gentoolkit, com esta ferramenta conseguimos descobrir muita informação [...]]]></description>
			<content:encoded><![CDATA[<p>O gentoo possui um ótimo gerenciador de pacotes, diga-se de passagem foi um dos <a href="http://petryx.blogrs.com.br/2008/06/02/5-motivos-para-adorar-o-gentoo/">5 motivos que me fez usa-lo</a>. A idéia deste post é mostrar como gerenciar os pacotes instalados de forma simples.</p>
<p>Para gerenciar os pacotes os desenvolvedores do gentoo fizeram uma excelente ferramenta a <strong>Gentoolkit</strong>, com esta ferramenta conseguimos descobrir muita informação sobre os pacotes como por exemplo: tamanho do pacote instalado, integridade do pacote, descobrir a qual pacote um arquivo pertence, mostrar as dependências de um pacote,  mostrar quais pacotes usam uma flag <strong>USE</strong> específica,  calcular a dependência reversa, etc &#8230;<br />
Existe um outro pacote que se chama <strong>portage-utils</strong> que também possui muitas ferramentas úteis para gerenciar pacotes o qual falarei em um próximo post.  </p>
<p><span id="more-64"></span><br />
<strong>Instalando o gentoolkit</strong></p>
<pre name="code" class="bash">
emerge gentoolkit
</pre>
<p>Não poderia deixar de comentar, sobre uma ferramenta muito boa de usar que é o <strong>eix</strong>(Ebuild IndeX), essa ferramenta cria um banco de dados dos pacotes, agilizando a procura.</p>
<p><strong>Instalando o eix</strong></p>
<pre name="code" class="bash">
USE="sqlite" emerge eix
</pre>
<p>Após instalar podemos rodar o comando <strong>eix-sync</strong> para sincronizar o <strong>emerge</strong> e criar o index do <strong>eix</strong>.</p>
<p>O <strong>eix</strong> pode ser usado no lugar do comando <strong>emerge -s package</strong> ou  <strong>emerge -S package</strong> a resposta será bem mais rápida a sintaxe é<br />
<strong>eix package</strong>.</p>
<p>Vamos descobrindo todos os <strong>pacotes instalados</strong>, rode o seguinte comando:</p>
<pre name="code" class="bash">
 eix -I
</pre>
<p>Este comando mostra todos os pacotes instalados, as flags <strong>USE</strong> que foram usadas para instalar e se existe um update para o pacote.</p>
<p><strong>Quero descobir a qual pacote pertence o arquivo  ntlm_auth ?</strong></p>
<pre name="code" class="bash">
equery belongs ntlm_auth
[ Searching for file(s) ntlm_auth in *... ]
net-fs/samba-3.0.28a (/usr/bin/ntlm_auth)
localhost ~ #
</pre>
<p>Descobrimos que o ntlm_auth pertence ao samba, podemos descobrir agora como está a integridade do pacote samba.</p>
<pre name="code" class="bash">
equery check samba
[ Checking net-fs/samba-3.0.28a ]
!!! /var/run/samba/.keep_net-fs_samba-0 does not exist
!!! /etc/samba/smb.conf.example has incorrect md5sum
 * 215 out of 217 files good
</pre>
<p>Olha só está dizendo que o smb.conf.example está com um md5 diferente, essa funcionalidade é ótima para encontrar rootkits, mas nesse caso fui eu que alterei o arquivo para ver se ele encontraria algo diferente. </p>
<p>O comando informou que o pacote samba tem 215 arquivos. Quais são eles ?</p>
<pre name="code" class="bash">
equery files samba
[ Searching for packages matching samba... ]
* Contents of net-fs/samba-3.0.28a:
/etc
/etc/conf.d
/etc/conf.d/samba
/etc/init.d
/etc/init.d/samba
/etc/pam.d
/etc/pam.d/samba
/etc/samba
/etc/samba/lmhosts
/etc/samba/smb.conf.example
/etc/samba/smbusers
/etc/xinetd.d
...
...
...
</pre>
<p>Mostrei somente uma parte dos arquivos, também podemos saber quais pacotes dependem do samba.</p>
<pre name="code" class="bash">
equery depends samba
[ Searching for packages depending on samba... ]
dev-libs/cyrus-sasl-2.1.22-r2 (ntlm_unsupported_patch? >=net-fs/samba-3.0.9)
gnome-base/gnome-vfs-2.22.0 (samba? >=net-fs/samba-3)
gnome-base/gvfs-0.2.4 (samba? >=net-fs/samba-3)
kde-base/kdebase-3.5.8-r6 (samba? >=net-fs/samba-3.0.4)
kde-base/kdebase-kioslaves-4.0.0 (samba? >=net-fs/samba-3.0.1)
media-libs/xine-lib-1.1.10.1-r1 (samba? net-fs/samba)
media-video/mplayer-1.0_rc2_p26753 (samba? net-fs/samba)
net-print/cups-1.3.7-r1 (samba? >=net-fs/samba-3.0.8)
localhost ~ #
</pre>
<p>Também pode-se mostrar a dependência direta e indireta</p>
<pre name="code" class="bash">
equery depgraph samba
</pre>
<p>Podemos descobrir o tamanho do pacote samba.</p>
<pre name="code" class="bash">
equery size samba
[ Searching for packages matching samba... ]
* size of net-fs/samba-3.0.28a
           Total files : 216
           Inaccessible files : 1
           Total size  : 49535.03 KiB
</pre>
<p>Seguindo quero saber quais pacotes estão compilados com a flag<strong> USE python</strong>.</p>
<pre name="code" class="bash">
equery uses python
[ Searching for packages matching python... ]
[ Colour Code : set unset ]
[ Legend : Left column  (U) - USE flags from make.conf              ]
[        : Right column (I) - USE flags packages was installed with ]
[ Found these USE variables for dev-lang/python-2.4.4-r7 ]
 U I
 + + berkdb       : Adds support for sys-libs/db (Berkeley DB for MySQL)
 - - bootstrap    : !!internal use only!! DO NOT SET THIS FLAG YOURSELF!, used during original system bootstrapping [make stage2]
 - - build        : !!internal use only!! DO NOT SET THIS FLAG YOURSELF!, used for creating build images and the first half of bootstrapping [make stage1]
 - - doc          : Adds extra documentation (API, Javadoc, etc)
 - - elibc_uclibc : <unknown>
 - - examples     : Install examples, usually source code
 + + gdbm         : Adds support for sys-libs/gdbm (GNU database libraries)
 + + ipv6         : Adds support for IP version 6
 + + ncurses      : Adds ncurses support (console display library)
 - - nocxx        : Disable support for C++ (DON'T USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING)
 - - nothreads    : Disable threads (DON'T USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING)
</pre>
<p>Finalmente vamos verificar se todos os pacotes que estão instalados no sistema estão com as dependências corretas. Iremos rodar o <strong>revdep-rebuild -p</strong> em modo pretend desta forma se encontrar algum pacote com uma dependência quebrada ele irá perguntar se desejamos instalar as dependências que estão faltando.</p>
<pre name="code" class="bash">
revdep-rebuild -p
</pre>
<p>Este post não cobre todas as possibilidades  de gerenciamento dos pacotes no gentoo pretendo continuar em outros posts.</p>
<p>Referências</p>
<p><a href="http://www.gentoo.org/doc/en/gentoolkit.xml">http://www.gentoo.org/doc/en/gentoolkit.xml</a><br />
<a href="http://pt-br.gentoo-wiki.com/Equery">http://pt-br.gentoo-wiki.com/Equery</a><br />
<a href="http://linuxreviews.org/gentoo/emerge/">http://linuxreviews.org/gentoo/emerge/</a><br />
<a href="http://vivaolinux.com.br/artigos/verArtigo.php?codigo=8440">http://vivaolinux.com.br/artigos/verArtigo.php?codigo=8440</a><br />
<a href="http://www.linux.com/feature/56270">http://www.linux.com/feature/56270</a><br />
<a href="http://linuxtidbits.wordpress.com/2008/03/21/gentoo-helpful-tidbits/">http://linuxtidbits.wordpress.com/2008/03/21/gentoo-helpful-tidbits/</a><br />
<a href="http://www.gentoo.org/doc/en/portage-utils.xml">http://www.gentoo.org/doc/en/portage-utils.xml</a></p>
<p>Caso tenha alguma dúvida, crítica ou sugestão deixe um comentário.<br /></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/07/03/gerenciando-pacotes-no-gentoo/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>C chat with sockets and thread</title>
		<link>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/</link>
		<comments>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/#comments</comments>
		<pubDate>Sun, 29 Jun 2008 01:13:16 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Sem categoria]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[developer]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=61</guid>
		<description><![CDATA[I developed a chat server in the C language and Python language The chat written in Python is posted here. Now I developed the chat using the C sockets and threads. The code developed in C follows the same principles of the code in Python. In C had to develop a double linked list to [...]]]></description>
			<content:encoded><![CDATA[<p>I developed a chat server in the C language and Python language The chat written in Python is posted  <a href="http://petryx.blogrs.com.br/2008/05/30/tutorial-write-a-multithread-chat-in-python/">here</a>. Now I developed the chat using the C sockets and threads.  The code developed in C follows the same principles of the code in Python. In C had to develop a double linked list to store the file descriptor of the socket, user name and nickname.  This code was developed to the discipline of Distributed Systems.</p>
<pre name="code" class="C">
#include
<pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/wait.h>
#include <stddef.h>
#include <errno.h>
#include <sys/un.h>

#include "listaDDE.h"
#define MYPORT 5800    // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold
#define MAXLINE 1024
#define NUM_THREADS     50
fd_set rmask;
pthread_mutex_t mutexsum;
pthread_mutex_t mutexLogin;
int fd_max;
int maxfds;

int sockfd;
fd_set read_fds;
fd_set master;
nodo *root = NULL;
static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static void *sendMensagem(void *arg);
void sigchld_handler(int s);
static void *sendALL(char msg[],int soks);
static void *sendMensagem(void *arg);
static void *newClientConnect(int arg);

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

void *sendALL(char msg[],int soks)
{
	nodo *aux = getFirst();
	while(aux != NULL)
	{
		int soc =aux->socket;

		if(soc != soks)
			{
	      	       		if(write(soc, msg, strlen(msg)) == -1)
		    			perror("send");
				printf("send %s %s\n",msg,aux->nick);

			}
		aux = aux->prox;
	}
}

void *sendMensagem(void *arg)
{
  char *buff;
  int fd = (*(int *) arg);
  int nbytes;
  char tmp[5000];

  printf("\nthread call %d",fd);
  newClientConnect(fd);
  printf("\n entry LOOP\n");
  nodo *cliente = busca(fd);

while(1)
{

     buff = (char *) calloc( MAXLINE,sizeof(char));
     if(FD_ISSET(fd,&#038;master))
     {
         nbytes = recv(fd,buff, MAXLINE -1 , 0);
	 if(nbytes > 1)
	 {

	   if(!tmp)
	   {
		perror("alocation:");
		exit(-1);
	   }
           strcat(tmp, cliente->nick);
	   strcat(tmp, " >> ");
	   strcat(tmp, buff);
           sendALL(tmp,fd);
	 }
	 else
	 {
	       if (nbytes == 0) {
                       printf ("servidor: socket %d desligado\n",  fd);
               } else {
                       perror ("recv");
               }
              close (fd); // BYE!!
              FD_CLR( fd , &#038;master);
	      removi(getFirst(),fd);
	      pthread_exit(NULL);
	  }

     }
     free(buff);

}

}

static void *newClientConnect(int arg)
{
	int fd = arg;
	pthread_t tid;
	struct sockaddr_in their_addr;
	char welcome[] = "Welcome Chat SistDistribuidos 0.1 \n";
	char msg1[] = "Login: ";
	char msg2[] = "NickName: ";
	char nome[100];
	char nick[100];
	int nbytes;
	socklen_t sin_size;

	pthread_mutex_lock (&#038;mutexLogin);

		printf("\naccept \n");
		if (write(fd, welcome, sizeof welcome - 1) != sizeof welcome - 1) {
	   		perror("write:");
			exit(1);
		}		

		printf("write %s \n",welcome);
		usleep(1000);

		if (write(fd, msg1, strlen(msg1)) != strlen(msg1)) {

	   		perror("write:");
			exit(1);
		}

		printf("write %s \n",msg1);
		usleep(1000);
		if ((nbytes = recv(fd, nome, 100,0)) < 0) {
		perror("read:");
	        exit(1);
	   	return;
		}
		nome[nbytes -1] = '\0';
		printf("Read %d %s\n",strlen(nome),nome);
		usleep(1000);
		if (write(fd, msg2, sizeof msg2 - 1) != sizeof msg2 - 1) {
	        	perror("write:");
	   	exit(1);
		}

		if ((nbytes =recv(fd, nick, 100,0)) < 0) {
	  	perror("read:");
		 exit(1);
		}
		nick[nbytes-1]='\0';
		printf("Read %d %s\n",strlen(nick),nick);		

		inseri(&#038;root,fd,nome,nick, inet_ntoa(their_addr.sin_addr));
		FD_SET(fd, &#038;master);		/* listen to this socket too */

	printf("end welcome \n");

	pthread_mutex_unlock (&#038;mutexLogin);

}

int main(void)
{
      // listen on sock_fd, new connection on new_fd
    int j,new_fd;
    struct timeval waitd;
    int nbytes;
    char buf[256];
    int fd_max; //numero maximo de descritores

    struct sockaddr_in my_addr;    // my address information
    struct sockaddr_in their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;

    FD_ZERO(&#038;master);
    FD_ZERO(&#038;read_fds);

    pthread_mutex_init(&#038;mutexsum, NULL);
    pthread_mutex_init(&#038;mutexLogin,NULL);

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , &#038;yes , sizeof ( int ) ) == -1 )
    {
		perror ( " setsockopt " );
		exit ( 1 );
    }

    my_addr.sin_family = AF_INET;         // host byte order
    my_addr.sin_port = htons(MYPORT);     // short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);

    if (bind(sockfd, (struct sockaddr *)&#038;my_addr, sizeof my_addr) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    FD_SET(sockfd, &#038;master);

    fd_max = sockfd;	

    int rc =0;	 

    int i = 0;
    int ret;

    int fd;
      waitd.tv_sec = 1;
      waitd.tv_usec = 0;

     while(1)
     {  

        read_fds = master;
        if (select (fd_max+1,  &#038;read_fds, NULL, NULL, NULL)== -1) {
                perror ("select");
                exit(1);
        }

        int addrlen = sizeof (their_addr);
        if (( new_fd = accept(sockfd,(struct sockaddr *)&#038;their_addr,&#038;addrlen)) == -1)  {
            perror ("accept");
        } else {

            FD_SET ( new_fd , &#038;master);

            printf ("server : new connection %s socket %d\n",
                              inet_ntoa (their_addr.sin_addr),new_fd);

	    pthread_t tred;
	    rc = pthread_create( &#038;tred, NULL,sendMensagem, (void *) &#038;new_fd);
       	    if (rc){
        	printf("ERROR; return code from pthread_create() is %d\n", rc);
       		exit(-1);
            }

        }
      } 

pthread_mutex_destroy(&#038;mutexsum);
pthread_mutex_destroy(&#038;mutexLogin);

    return 0;
}
</pre>
<p>Header Double Linked List name ListaDDE.h</p>
<pre  name="code" class="C">
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAXBUFFER 2048

typedef struct cel
{
	int socket;
	char nome[50];
	char nick[50];
	char host[50];
	char buff[MAXBUFFER];
	struct cel *ante;
       	struct cel *prox;
}nodo;

nodo *getFirst();
nodo *getLast();
nodo *busca(int key);

void inseri(nodo **root, int socket,char nome[],char nick[],char host[]);

void removi(nodo *root, int socket);
void print (nodo *ini);
</pre>
<p>Implementation Double Linked List without use global variable</p>
<pre name="code" class="C">
#include <string.h>
#include <stdlib.h>
#include "listaDDE.h"

nodo *first = NULL, *last = NULL;

nodo *getFirst()
{
	printf("call getFirst()\n");
	return first;
}

nodo *getLast()
{
	return last;
}
void inseri(nodo **root, int socket, char nome[],char nick[],char host[])
{
	nodo *aux;
	//primeira inserção
	if(*root == NULL)
	{
		*root = (nodo *) malloc(sizeof (nodo));
		if(*root == NULL)
		{
			perror("erro de alocação\n");

		}
		(*root)->socket = socket;
		strcpy((*root)->nome , nome);
		strcpy((*root)->nick , nick);
	        strcpy((*root)->host , host);
		(*root)->prox = NULL;
		(*root)->ante = NULL;
		 first = (*root);
		last = first;

	}
	else
	{
		aux = (nodo *) malloc(sizeof (nodo));
		if(aux == NULL)
		{
			perror("erro de alocação\n");

		}
		aux->socket = socket;
		strcpy(aux->nome , nome);
		strcpy(aux->nick , nick);
	        strcpy(aux->host , host);

		aux->ante =last;
            	aux->prox = NULL;

                last->prox = aux;
            	last = aux;
		*root = last;
	}
}

void removi(nodo *primeiro,int dado)
{
   nodo *aux = primeiro;
   while(aux != NULL)
   {
       if(dado == aux->socket &#038;&#038; aux == first) //Remove first element
      {

	 if(aux->prox != NULL)
	 {
		printf("!= null\n");
		aux->prox->ante = NULL;
	        first = aux->prox;
	 }
	 else
	 {
		printf("null\n");
		free(first);

		break;
	 }

      }
      else if(dado == aux->socket &#038;&#038; aux->prox == NULL) //remove last
      {
      	 aux->ante->prox = NULL;
         last = aux->ante;
         free(aux);
         break;
      }
      else if(dado == aux->socket &#038;&#038;  aux->prox != NULL &#038;&#038; aux->ante !=NULL) //remove middle
      {
      	aux->ante->prox = aux->prox;
         aux->prox->ante = aux->ante;
         free(aux);
         break;
      }

      aux = aux->prox;
   }
}

void print (nodo *ini)
{
   nodo *p = first;
   while(p != NULL)
   {   printf ("socket %d cliente %s\n", p->socket,p->nome);
	p = p->prox;    

   }
}

nodo *busca (int key)
{
   nodo *p = getFirst();
   int flag = 0;
   while(p != NULL)
   {
   	if(p->socket == key)
	{
		return p;
	}
	p = p->prox;    

   }
   return NULL;
}
</pre>
<p>In order to compile this code together use the follow command  <strong>gcc -o chatserver server.c listaDDE.c -lpthread</strong><br />
Using  On the server<br />
 <strong>./chatserver </strong> </p>
<p>On the client <strong>telnet ipServer 5800 </strong> </p>
<p>Digg if you like it:<a href="http://digg.com/programming/Development_of_a_chat_with_the_C_sockets_and_Threads"> Development of a chat with the C sockets and Threads</a></p>
<p>UPDATE: This code is avaible in <a href="http://github.com/petryx/petryx.blogrs.com.br/tree/e5eeb098f5bf0f50e2fb9113a7f09b8ebd2e877e/sockets/C/chatC">http://github.com/petryx/</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/06/28/c-chat-with-sockets-and-thread/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Balanceando 2 links no Linux</title>
		<link>http://petryx.blogrs.com.br/2008/06/22/balanceando-2-links-no-linux/</link>
		<comments>http://petryx.blogrs.com.br/2008/06/22/balanceando-2-links-no-linux/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 00:27:20 +0000</pubDate>
		<dc:creator>Marlon Petry</dc:creator>
				<category><![CDATA[Dicas Linux]]></category>
		<category><![CDATA[Sem categoria]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=51</guid>
		<description><![CDATA[Nesta matéria pretendo mostrar como fazer balanceamento entre links, utilizando uma máquina com o Linux instalado. A imagem abaixo mostra a topologia de rede, nesta configuração temos uma Linux Box com três placas de redes eth1 para os clientes, eth0 para o link1 e eth2 para o link2. O link1 é 2 vezes mais rápido [...]]]></description>
			<content:encoded><![CDATA[<p>Nesta matéria pretendo mostrar como fazer balanceamento entre links, utilizando uma máquina com o Linux instalado. </p>
<p>A imagem abaixo mostra a topologia de rede, nesta configuração temos uma Linux Box com três<br />
placas de redes eth1 para os clientes, eth0 para o link1 e eth2 para o link2. O link1 é 2 vezes mais rápido que o link2.<br />
<a href='http://petryx.blogrs.com.br/wp-content/uploads/2008/06/topologia_rede_balaceamento1.jpg'><img src="http://petryx.blogrs.com.br/wp-content/uploads/2008/06/topologia_rede_balaceamento1.jpg" alt="balaceamento de links na internet" title="topologia_rede_balaceamento1" width="450" height="164" class="alignnone size-medium wp-image-53" /></a></p>
<p>Existem várias técnicas que podem realizar balanceamento entre links como por exemplo: <strong>bonding, roteamento avançado</strong>. Irei utilizar roteamento avançado porque com <strong>port bonding</strong> não descobri como configurar o peso de cada link. </p>
<p><strong>Bonding</strong></p>
<p>Este método permite criar uma uma interface lógica de rede que agrega dois ou mais links físicos conectados a switchs separados. Mais detalhes sobre <strong><a href="http://www.sistemasabertos.com.br/~mario/balanceamento.html">bonding</a> </strong></p>
<p><strong>Roteamento avançado Linux</strong></p>
<p>Linux possui recursos avançados para roteamento esses recursos estão implementados no kernel, então eles devem estar habilitados. Para saber mais sobre roteamento avançado acesso <a href="http://lartc.org/lartc.html">http://lartc.org/lartc.html </a></p>
<p>Então vamos colocar a mão na massa.</p>
<p><strong>Pré-requisitos</strong></p>
<p><strong>Kernel</strong></p>
<p>As seguintes opções devem estar habilitadas:</p>
<ul>
<li> CONFIG_IP_ADVANCED_ROUTER (Networking/IP: Advanced Router) </li>
<li>CONFIG_IP_MULTIPLE_TABLES (Networking/IP: policy routing) </li>
</ul>
<p>Estas opções habilitam o roteamento avançado e também possibilitam ter múltiplas tabelas de roteamento.</p>
<p>Para verificar se o seu kernel está compilado com estes recursos rode o seguinte comando:</p>
<pre name="code" class="sh">
grep -e CONFIG_IP_ADVANCED_ROUTER -e CONFIG_IP_MULTIPLE_TABLES /usr/src/linux/.config
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
</pre>
<p>Se estes recursos não estiverem habilitados será necessário recompilar o kernel habilitando estes recursos. Rode os seguintes comandos para recompilar o kernel com estas opções.</p>
<p><strong>cd /usr/src/linux<br />
make menuconfig</strong></p>
<p>Navegue para <strong>Network&#8211;></strong><br />
<strong>Network Options &#8211;></strong> e modifique as opções<br />
<strong>IP: Advanced router</strong> para [*] e<br />
<strong>IP: policy routing para [*]<br />
</strong>
</pre>
<p>Salve e rode <strong>make &#038;&#038; make modules_install</strong></p>
<p><strong>IPROUTE2</strong></p>
<p>Verifique se o iproute2 está instalado com o comando <strong>ip</strong>. Caso não esteja instalado neste <a href="http://www.policyrouting.org/iproute2.doc.html">site</a> possui uma ótima documentação sobre o <a href="http://www.policyrouting.org/iproute2.doc.html">iproute2</a>.</p>
<p><strong>Definindo a tabela de Rotas</strong></p>
<p>Vamos criar duas tabelas de rotas dentro do arquivo /etc/iproute/rt_tables</p>
<pre name="code" class="bash">
echo "1 Link1" >> /etc/iproute/rt_tables
echo "2 Link2" >> /etc/iproute/rt_tables
</pre>
<p>A partir de agora temos três tabelas de rotas <strong>Link1</strong> e <strong>Link2</strong>.</p>
<p>A próxima etapa é preencher a tabela de rotas.</p>
<p><strong>Rota Link1</strong></p>
<pre name="code" class="sh">
/sbin/ip route add 200.xx.yy.0/24 dev eth0 src 200.xx.yy.2 table link1
/sbin/ip route add default via 200.xx.yy.1 table link1
/sbin/ip rule add from  200.xx.yy.2 table link1
</pre>
<p><strong>Rota Link2</strong></p>
<pre name="code" class="sh">
/sbin/ip route add 190.xx.yy.0/24 dev eth0 src 190.xx.yy.2 table link2
/sbin/ip route add default via 190.xx.yy.1 table link2
/sbin/ip rule add from  190.xx.yy.2 table link1
</pre>
<p><strong>Balanceando</strong></p>
<p>Para balancear o uso dos links devemos atribuir o peso de cada link. O peso é atribuído através do parâmetro <strong>weight</strong> no nosso exemplo vamos utilizar o peso 2 para o link1 e 1 para o link 2.</p>
<pre name="code" class="sh">
/sbin/ip route add default scope global\
         nexthop via 200.xx.yy.1 dev eth0 weight 2\
         nexthop via 190.xx.yy.1 dev eth1 weight 1
</pre>
<p>Script completo</p>
<pre name="code" class="sh">
#!/bin/bash
#
#Script para balanceamento de 2 links de acesso a internet
#Licença=GPL
#Author=Marlon Petry

NETMASK1=200.xx.yy.0/24
DEVICE1=eth0
IPADDRESS1=200.xx.yy.2
GATEWAY1=200.xx.yy.1
TABLE1=Link1

NETMASK2=190.xx.yy.0/24
DEVICE2=eth2
IPADDRESS2=190.xx.yy.2
GATEWAY2=190.xx.yy.1
TABLE2=Link2

#PESO DOS LINKS
W1=2
W2=1

#interface 1
/sbin/ifconfig eth0 down
/sbin/ifconfig eth0 $IPADDRESS1/29  up
/sbin/ip route add $NETMASK1 dev $DEVICE1 src $IPADDRESS1 table $TABLE1
/sbin/ip route add default via $GATEWAY1 table $TABLE1
/sbin/ip rule add from $IPADDRESS1 table $TABLE1

#Interface 2
/sbin/ifconfig eth2 down
/sbin/ifconfig eth2 $IPADDRESS2/29 up
/sbin/ip route add $NETMASK2 dev $DEVICE2 src $IPADDRESS2 table $TABLE2
/sbin/ip route add default via $GATEWAY2 table $TABLE2
/sbin/ip rule add from $IPADDRESS2 table $TABLE2

#Adicionando as rotas e o balanceamento de carga
/sbin/ip route add default scope global\
         nexthop via $GATEWAY1 dev $DEVICE1 weight $W1\
         nexthop via $GATEWAY2 dev $DEVICE2 weight $W2

echo "Balanceamento 2 link petryx.blogrs.com.br"
</pre>
<p>O balanceamento de links através de roteamento funciona bem, mas segundo o how-to <a href="http://lartc.org/lartc.html">http://lartc.org/lartc.html</a> não é perfeito, pois as rotas são cacheadas. Isto significa que quando um site for acessado através do link1, sempre será acessado através da mesma rota. Este problema pode ser resolvido com a aplicação de um patch disponível no site <a href="http://www.ssi.bg/~ja/#routes">http://www.ssi.bg/~ja/#routes</a>. </p>
<p>Precisando de Consultoria em Linux entre em contato <a href="http://petryx.blogrs.com.br/consultoria/">aqui</a>.</p>
<p><strong>Saiba mais</strong></p>
<p><a href="http://www.linuxhorizon.ro/iproute2.html">http://www.linuxhorizon.ro/iproute2.html</a><br />
<a href="http://lartc.org/lartc.html">http://lartc.org/lartc.html</a><br />
<a href="http://linux-ip.net/html/routing-intro.html">http://linux-ip.net/html/routing-intro.html</a><br />
<a href="http://www.rnp.br/newsgen/0201/roteamento_linux.html">http://www.rnp.br/newsgen/0201/roteamento_linux.html</a><br />
<a href="http://www.linuxjournal.com/article/5826">http://www.linuxjournal.com/article/5826</a></p>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/06/22/balanceando-2-links-no-linux/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Tutorial Postfix Iniciante</title>
		<link>http://petryx.blogrs.com.br/2008/05/17/tutorial-postfix-iniciante/</link>
		<comments>http://petryx.blogrs.com.br/2008/05/17/tutorial-postfix-iniciante/#comments</comments>
		<pubDate>Sun, 18 May 2008 01:07:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tutoriais]]></category>

		<guid isPermaLink="false">http://petryx.blogrs.com.br/?p=7</guid>
		<description><![CDATA[Este é um tutorial sobre postfix bem básico não implementamos verificação de spam, antivírus. Não é aconselhável colocar um servidor no ar com estas configurações. Postfix é um MTA(Mail Transfer Agent), sendo uma alternativa ou sendmail, qmail e outros. Tem como vantagens estabilidade, seguranca e fácil configuraçao Neste tutorial mostraremos como compilar e configurar o [...]]]></description>
			<content:encoded><![CDATA[<p>Este é um tutorial sobre postfix bem básico não implementamos verificação de spam, antivírus.</p>
<p>Não é aconselhável colocar um servidor no ar com estas configurações.</p>
<p>Postfix é um MTA(Mail Transfer Agent), sendo uma<br />
alternativa ou sendmail, qmail e outros. Tem como vantagens<br />
estabilidade, seguranca e fácil configuraçao</p>
<p>Neste tutorial mostraremos como compilar e configurar o servidor<br />
de email Postfix, nas suas configurações básicas:</p>
<p>1) Passo realizar o download da ultima release estavel</p>
<pre name="code" class="bash">
wget ftp://ftp.pucpr.br/postfix/official/postfix-2.4.5.tar.gz
</pre>
<p>2) Após concluído o download devemos realizar um backup dos<br />
arquivos de configuraçãoo do sendmail, se estiver instalado</p>
<pre name="code" class="bash">
mv /usr/sbin/sendmail /usr/sbin/sendmail.OFF

mv /usr/bin/newaliases /usr/bin/newaliases.OFF

mv /usr/bin/mailq /usr/bin/mailq.OFF

chmod 755 /usr/sbin/sendmail.OFF /usr/bin/newaliases.OFF /usr/bin/mailq.OFF
</pre>
<p>3)Mover e descompactar os fontes</p>
<pre name="code" class="bash">

mv postfix-2.4.5.tar.gz /usr/src
cd /usr/src
tar -xzvf postfix-2.4.5.tar.gz
</pre>
<p>4)Como padrão no Linux sempre acompanha os fontes o arquivo<br />
INSTALL que mostra detalhes da compilação do pacote</p>
<pre name="code" class="bash">
less INSTALL
make -f Makefile.init makefiles
make
</pre>
<p>Antes de executar o make install devemos criar o usuário postfix</p>
<p>Acrescentar a seguinte linha no passwd</p>
<pre name="code" class="bash">
vim /etc/passwd
postfix:*:12345:12345:postfix:/no/where:/no/shell
</pre>
<p>Acrescentar o grupo</p>
<pre name="code" class="bash">
#vim /etc/group
postfix:*:12345:
postdrop:*:54321:
</pre>
<p>6) Ao executar o make install será solicitado os caminhos do servidor de email neste caso usaremos os padrões do  postfix</p>
<pre name="code" class="bash">
make install

install_root: [/]tempdir: o diretório de origem da instalação
config_directory: [/etc/postfix]
daemon_directory: [/usr/libexec/postfix]
command_directory: [/usr/sbin]
queue_directory: [/var/spool/postfix]
sendmail_path: [/usr/sbin/sendmail]
newalises_path: [/usr/bin/newaliases]
mailq_path: [/usr/bin/mailq]
mail_owner: [postfix]
setgid_group: [postdrop]
html_directory: [/var/www/htdocs/postfix/]
manpage_directory: [/usr/local/man]

readme_directory: [/etc/postfix]
</pre>
<p>A partir daqui o postfix já esta compilado e instalado só falta configurar</p>
<pre name="code" class="bash">
vim  /etc/postfix/main.cf

myhostname = localhost
mydomain = localdomain.com.br
mydestination = $myhostname, localhost.$mydomain, $mydomain,
mail.$mydomain

#Parametro para configurar as redes que serao aceitas no servido de email
mynetworks = 127.0.0.0/8

#Configuração para restricao de envio de email

smtpd_recipient_restrictions = permit_mynetworks,check_client_access,hash:/etc/postfix/client_access
check_relay_domains
#Local de entrega dos emails
mail_spool_directory = /var/spool/mail
</pre>
<p>Após realizada as configurações podemos verificar se existe algum erro de configuração com o comando</p>
<pre name="code" class="bash">
postfix check
</pre>
<p>Não havendo erros podemos iniciar o servidor de email</p>
<pre name="code" class="bash">
postfix start
</pre>
<p>Para verificar o funcionamento podemos executar o comando</p>
<pre name="code" class="bash">
netstat -vantu
</pre>
<p>Este comando mostra todos as conexoes tcp e udp na maquina devemos procurar pela porta 25</p>
<p>Testando o servidor</p>
<pre name="code" class="bash">
telnet 127.0.0.1 25

helo  a resposta deve ser a seguinte 250 OK

mail from:
aresposta deve ser a seguinte 250 OK - mail from

rcpt to:
a resposta deve ser a seguinte 250 OK - Recipient

data
a resposta deve ser a seguinte 354 Send data. Finalizar com
.

quit
</pre>
<p>OK servidor testado, verifique se recebeu a mensagem</p>
<p>Outra forma de verificar o funcionamento é através do logs</p>
<pre name="code" class="bash">
tail -f /var/logs/mail/info
</pre>
]]></content:encoded>
			<wfw:commentRss>http://petryx.blogrs.com.br/2008/05/17/tutorial-postfix-iniciante/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
