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 plpgsql;
r := addTest(1,1);
RAISE NOTICE 'addTest = %',r;
r := addTest(2,2);
RAISE NOTICE 'addTest = %',r;
RETURN r;
END global;
$$ LANGUAGE 'plpgsql';
Na função acima criei uma função aninhada chamada addTest(REAL,REAL) 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:
SELECT testNestedFunction();
NOTA: addTest = 2
NOTA: addTest = 4
Tempo total de execução da consulta: 18 ms.
1 registros recuperados.
Como pode ser visto foi realizado duas chamadas a função aninhada addTest() passando diferentes parâmetros.
O interessante é que o Postgresql cria duas funções: testNestedFunction() e addTest(REAL,REAL). E não somente uma função aninhada, isso favorece aos bugs, vamos simular um então.
Vamos deletar a função addTest(REAL,REAL) e executar novamente.
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
O comando DROP FUNCTION addTest(REAL,REAL) não verificou que a função testnestedfunction() é 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 addTest() não existe até a primeira execução, ou seja, quando o comando é executado SELECT testnestedfunction() pela primeira vez a função addTest() é criada. Então quando deletamos a função addTest() e executamos novamente o comando SELECT testnestedfunction(), a função addTest() não é criada novamente.
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.
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.
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.
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:
<
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:
CREATE OR REPLACE FUNCTION test() RETURNS VOID as
$$
<>
DECLARE
v_test REAL;
BEGIN
v_test := 1;
<>
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';
Resultado da execução:
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.
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.
É 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.
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 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.
A documentação da Api Jamod é boa, possui vários códigos de exemplo para implementar ModBus Escravo e Modbus Mestre.
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 utilizar a linguagem nativa do PostgreSQL que PL/PGSQL.
Habilitando a linguagem em uma bases de dados.
create lang plpgsql nomedabasededados
Por exemplo na base de dados book
create lang plpgsql book
Este comando deve ser executado no shell.
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.
Voltando ao exemplo vamos desenvolver o algoritmo da torre de hanoi em PL/PGSQL.
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';
Executando a função select towerHanoi(3,1,2,3);
Veja o resultado da função
NOTA: DISK 1 Move da haste 1 para haste 2 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform NOTA: DISK 2 Move da haste 1 para haste 3 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform NOTA: DISK 1 Move da haste 1 para haste 3 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform NOTA: DISK 3 Move da haste 1 para haste 3
NOTA: DISK 1 Move da haste 1 para haste 3 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform NOTA: DISK 2 Move da haste 1 para haste 1 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform NOTA: DISK 1 Move da haste 1 para haste 1 CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
Total query runtime: 2 ms.
Data retrieval runtime: 7 ms.
1 rows retrieved.
Esta simples função demonstra como usar recursividade, passagem de parâmetros e como chamar uma função em PL/PGSQL.
Estou pesquisando pra ver se consigo fazer uma árvore binária em PL/PGSQL. Quando eu conseguir coloco o algoritmo.
Abraços
Hei pessoal não se esqueçam a assinatura dos feeds é gratuita então não percam tempo.
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 alguns não terá novidade nenhuma nesta matéria, mas com certeza será valioso para alguém como foi para mim.
Antes de começar temos que entender como o postgresql gerencia os arquivos da base de dados, então vamos explora-lo.
Como PostgreSQL gerencia os arquivos da base de dados ?
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 postmaster.
E como fica essa hierarquia no disco ?
Para descobrir como funciona essa hierarquia na prática vamos fazer umas consultas (queries) , executar um comandos no shell.
Vamos começar conectando a base de dados e descobrindo o OID (Obect ID) através de uma consulta.
~$ psql book -U postgres
book=# SELECT datname, oid from pg_database;
datname
oid
postgres
10819
book
16384
template1
1
template0
10818
(4 registros)
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.
~$ cd $PG_DATA
~$ ls
base pg_clog pg_ident.conf pg_subtrans pg_twophase pg_xlog postmaster.opts
global pg_hba.conf pg_multixact pg_tblspc PG_VERSION postgresql.conf postmaster.pid
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á.
~$ cd base
~$ ls -la
drwx—— 2 postgres postgres 2648 Jul 11 11:17 1
drwx—— 2 postgres postgres 2648 Jul 11 11:17 10818
drwx—— 2 postgres postgres 2680 Jul 11 11:18 10819
drwx—— 2 postgres postgres 2680 Jul 11 11:39 16384
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.
Entrando no diretório 1 podemos ver que existem vários arquivos vamos descobrir o que significa cada um deles.
Na tabela pg_class existe mais informação que pode nos ajudar a explorar a estrutura de armazenamento do PostgreSQL.
psql book -Upostgres
book=# select relname,oid,relpages, reltuples FROM pg_class ORDER BY OID;
relname
oid
relpages
reltuples
pg_type
1247
5
242
pg_autovacuum
1248
0
0
pg_attribute
1249
28
1628
pg_autovacuum_vacrelid_index
1250
1
0
pg_proc
1255
45
1929
pg_class
1259
5
204
A coluna reltuples informa quantas tuplas tem em cada tabela. Já a coluna relpages mostra quantas páginas (pages) são requiridas para armazenar o conteúdo da tabela.
Qual a correspondência entre relpages e reltuples com o tamanho do arquivo no disco ?
Vamos listar o conteúdo do diretório e pegar dois exemplos
O arquivo chamado 1247 tabela pg_type ocupa um espaço em disco e 40960 bytes. Se dividirmos 40960/5 relpages = 8192 bytes, realizando o mesmo cálculo para a tabela pg_attribute que corresponde ao arquivo 1249 que possui um tamanho em disco de 229376 bytes / 28 relpages = 8192 bytes.
O tamanho 8192 refere-se ao tamanho da página este valor é fixo como podemos verificar.
Com esta matéria acho que consegui mostrar como o PostgreSQL estrutura os dados no disco.
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.
Referência:
Livro PostgreSQL – Korry Douglas e Susan Douglas
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.
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 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 USE específica, calcular a dependência reversa, etc …
Existe um outro pacote que se chama portage-utils que também possui muitas ferramentas úteis para gerenciar pacotes o qual falarei em um próximo post.
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 store the file descriptor of the socket, user name and nickname. This code was developed to the discipline of Distributed Systems.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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,&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 , &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 (&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(&root,fd,nome,nick, inet_ntoa(their_addr.sin_addr));
FD_SET(fd, &master); /* listen to this socket too */
printf("end welcome \n");
pthread_mutex_unlock (&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(&master);
FD_ZERO(&read_fds);
pthread_mutex_init(&mutexsum, NULL);
pthread_mutex_init(&mutexLogin,NULL);
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , &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 *)&my_addr, sizeof my_addr) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
FD_SET(sockfd, &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, &read_fds, NULL, NULL, NULL)== -1) {
perror ("select");
exit(1);
}
int addrlen = sizeof (their_addr);
if (( new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&addrlen)) == -1) {
perror ("accept");
} else {
FD_SET ( new_fd , &master);
printf ("server : new connection %s socket %d\n",
inet_ntoa (their_addr.sin_addr),new_fd);
pthread_t tred;
rc = pthread_create( &tred, NULL,sendMensagem, (void *) &new_fd);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
}
pthread_mutex_destroy(&mutexsum);
pthread_mutex_destroy(&mutexLogin);
return 0;
}
Header Double Linked List name ListaDDE.h
#include
#include
#include
#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);
Implementation Double Linked List without use global variable
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 que o link2.
Existem várias técnicas que podem realizar balanceamento entre links como por exemplo: bonding, roteamento avançado. Irei utilizar roteamento avançado porque com port bonding não descobri como configurar o peso de cada link.
Bonding
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 bonding
Roteamento avançado Linux
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 http://lartc.org/lartc.html
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.
cd /usr/src/linux
make menuconfig
Navegue para Network–> Network Options –> e modifique as opções IP: Advanced router para [*] e IP: policy routing para [*]
Salve e rode make && make modules_install
IPROUTE2
Verifique se o iproute2 está instalado com o comando ip. Caso não esteja instalado neste site possui uma ótima documentação sobre o iproute2.
Definindo a tabela de Rotas
Vamos criar duas tabelas de rotas dentro do arquivo /etc/iproute/rt_tables
A partir de agora temos três tabelas de rotas Link1 e Link2.
A próxima etapa é preencher a tabela de rotas.
Rota Link1
/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
Rota Link2
/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
Balanceando
Para balancear o uso dos links devemos atribuir o peso de cada link. O peso é atribuído através do parâmetro weight no nosso exemplo vamos utilizar o peso 2 para o link1 e 1 para o link 2.
/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
Script completo
#!/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"
O balanceamento de links através de roteamento funciona bem, mas segundo o how-to http://lartc.org/lartc.html 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 http://www.ssi.bg/~ja/#routes.
Precisando de Consultoria em Linux entre em contato aqui.
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 servidor
de email Postfix, nas suas configurações básicas:
1) Passo realizar o download da ultima release estavel
6) Ao executar o make install será solicitado os caminhos do servidor de email neste caso usaremos os padrões do postfix
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]
A partir daqui o postfix já esta compilado e instalado só falta configurar
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
Após realizada as configurações podemos verificar se existe algum erro de configuração com o comando
postfix check
Não havendo erros podemos iniciar o servidor de email
postfix start
Para verificar o funcionamento podemos executar o comando
netstat -vantu
Este comando mostra todos as conexoes tcp e udp na maquina devemos procurar pela porta 25
Testando o servidor
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
OK servidor testado, verifique se recebeu a mensagem
Outra forma de verificar o funcionamento é através do logs