[SP-pm] Socket - algumas questões:

Solli Honorio shonorio at gmail.com
Tue May 3 11:59:45 PDT 2011


2011/5/3 Andre Carneiro <andregarciacarneiro em gmail.com>

> Salve Monges!
>
>
> Estou com uns problemas com Sockets que mesmo fuçando bastante eu não
> consegui resolver. Os sockets tanto do lado do servidor quanto do lado do
> cliente estão ok, e isso significa:
>
> - O 'socket' do lado do 'client' escreve coisas no socket
> - O 'socket' do lado do server lê coisas do Socket;
>
> Agora eu preciso que o socket do lado do servidor envie os resultados como
> mensagens de erros e dados, de maneira geral, para o client. O que tá
> rolando agora:
>
>
> SERVER:
>
> <code>
> use strict;
> use warnings;
> use IO::Socket::INET
> use Daemon::Generic;
> use feature qw/ say switch /;
> .
> .
> .
> #configuração
> .
> .
> .
>     my $usock = IO::Socket::INET->new (
>                             Type => SOCK_STREAM ,
>                             LocalAddr => $config_socket->{ SocketBind },
>                             LocalPort => $config_socket->{ SocketPort },
>                             Proto => 'tcp',
>                             Listen => 1,
>                             ReuseAddr => 1,
>                 ) or die $!;
>
>
>   my $pid = fork;
>       if(!defined($pid)){
>         say "FATAL! Sem recursos para o fork! Abortando!";
>         exit 0;
>     }
>     elsif($pid == 0){
>         my $newconn = &get_conn();
>         while(1){
>             #uma 'pá' de coisa aqui no child...
>             sleep 60;
>         }
>         exit(1);
>     }
>     else {
>         my $r = undef;
>         while(1){
>             say "I'm working!";
>             if( $r = $usock->accept ){
>                 &process_commands($r, \$usock);
>             }
>             else {
>                 $logerr->write('error','Problemas com o socket! Abortando!'
> . $!);
>                 exit(0);
>             }
>             sleep 1;
>         }
> #        $usock->close;
>         close $out;
>
>         waitpid($pid,0);
>     }
>
>
>
> sub process_commands {
>     my $sh = shift;
>     my $rsock = shift;
>     my $res = 0;
>     while(<$sh>){
>         #tratando o que vem do client
>         my $out = $_ || 'none';
>         $out =~ s/^(\ |\t)+//;
>         my @params = split /\ +/, $out;
>         my ($command,$parameter) = ( $params[0],$params[1] );
>         #separando algumas informações
>         my %client_auth_data = (    host     => undef,
>                                     user     => undef,
>                                     password => undef,
>                                     port     => undef,
>                         );
>
>         #Implementar a camada de autenticação aqui.
>
>         given($command){
>             when( 'stopsafe' ){
>                 say 'Executando o stopsafe';
>                 if(!&pause_MTAs()){
>                          #enviar mensagem de erro via socket
>                 }
>                 else {
>                          #enviar mensagem de ok para o socket...
>                 }
>
>                 $res = 1;
>             }
>             #mais uma pancada de comandos aqui...
>             default {
>                 my $msg = "Comando inválido! '$command $parameter' ";
>             }
>         }
>     }
>     return $res;
> }
>
>
>
> </code>
>
>
> Resumo: Eu tenho um processo que fica executando várias outras coisas, e um
> outro só para ficar escutando comando vindo do socket do lado do CLIENT! O
> que eu quero fazer, imagino eu, seria gravar alguma coisa no socket de
> dentro dessa função 'process_commands'. E de alguma forma ler isso do
> client.
>
>
>
> CLIENT
>
> <code>
>     use strict;
>     use warnings;
>     use IO::Socket::INET;
>     .
>     .
>     .
>
>     my ($bind, $port ) = @_;
>     my $sock = IO::Socket::INET->new (
>                                 PeerAddr => $bind,
>                                 PeerPort => $port,
>                                 Proto => 'tcp',
>                                 Blocking    => 0,
>                                 ReuseAddr   => 1,
>                         ) or die $!;
>
>     $sock->send('chave1 valor1 chave2 valor2');
>
>     while(<$sock>){
> #Teoricamente deveria ter alguma coisa no socket, mas nao rola...
>     }
>
>     $sock->close();
>
>
> </code>
>
>
> Perguntas:
>
>
> - Como gravar no socket do lado do server, de modo que isso seja legível do
> lado do client?
>

Uma das maneiras é assim :

<code>

#!/usr/bin/env perl
use strict;
use IO::Socket::INET;

my $quit = 0;

$SIG{INT} = sub { $quit++ };

my $listen_socket = IO::Socket::INET->new(LocalPort => 2121,
                                        Listen    => 2,
                                        Proto     => 'tcp',
                                        Reuse     => 1,) or die "$!";

while ( !$quit ) {
  next unless my $connection = $listen_socket->accept;

  defined ( my $child = fork() ) or die "Can't fork: $!";

  if ( $child == 0 ) {
    $listen_socket->close;
    do_something($connection);
    exit 0;
  }

  $connection->close;

}

sub do_something {
  my $socket = shift;

  $socket->autoflush(1);
  $socket->print("Entre com os numeros para calculo:\n");

  while ( 1 ) {
    my $input = $socket->getline();
    exit 0 if $input =~ /quit/i;
    $socket->print($input);
  }

}

<code>

O código acima é um echo server muito simples, que ilustra bem uma
comunicação bi-direcional. Não sei onde você está utilizando este código,
mas eu recomendo muito cuidado. Existem vários problemas com código deste
tipo (I/O Blocking, por exemplo) e uma enorme quantidade de coisas que podem
ocorrer de errado.

Tenho um livro (Networking Programming with Perl) de 700 páginas só falando
de tudo que pode dar errado num código deste tipo e todas (ou quase)
variações de servidores escrito em Perl (tcp, udp, I/O Blocking, I/O
Nonblocking, forked, threaded). Utilizar print/getline, write/read,
syswrite/sysread é apenas o começo das perguntas de arquitetura que temos
que responder para um servidor.

Se for possível, eu recomendo fortemente que você utilize um framework para
fazer isto, tipo o POE (http://poe.perl.org/?POE_Cookbook/TCP_Servers tem um
exemplo do mesmo código que eu escrevi). Se não for possível, eu recomendo
você dar uma olhada no livro que eu disse (posso emprestar se for o caso).
Temos também o Mojolicious com os websocket (estou começando a ver isto),
pode ser uma boa alternativa.

- Preciso de protocolo específico para fazer isso ?
>

Uma conversa bi-direcional, você precisa definir os comandos que um vai
aceitar do outro. Você terá que criar algum protocolo de qualquer maneira,
uma linguagem que seja compreendida pelo servidor e cliente, qual como o
HTTP, FTP ou SMTP. Na transferência de arquivo, recomendo fortemente no
formato JSON. Aliais, este teu sistema não seria candidato para ser um
webapp com RESTfull web services implementado em Catalyst ou Mojolicious ?
Neste ambiente O URI é a função que recebe/retorna em JSON, sem view em html
!


> - Eu vi algumas pessoas usando udp ao invés de tcp alegando aumento de
> performance, mas abrindo mão de vários quesitos de segurança dentre outros
> problemas. Confirma?
>
>
Sim, o UDP é mais 'leve' do que o 'tcp'. Mas isto significa que você terá
que tratar tudo relacionado a transferência de dados (ordem dos pacotes,
perda dos pacotes, etc). Uma recomendação, a menos que você saiba muito bem
o que está fazendo, e que o consumo de rede seja justificado, não utilize o
UDP, o overhead para o programador não vale a pena. O HTTP utiliza TCP e
ninguém pensou em mudar isto, não siga os líderes :D ....


> Cheers!
>
>
> --
> André Garcia Carneiro
> Analista/Desenvolvedor Perl
> (11)82907780
>
> =begin disclaimer
>   Sao Paulo Perl Mongers: http://sao-paulo.pm.org/
>  SaoPaulo-pm mailing list: SaoPaulo-pm em pm.org
>  L<http://mail.pm.org/mailman/listinfo/saopaulo-pm>
> =end disclaimer
>
>


-- 
"o animal satisfeito dorme". - Guimarães Rosa
-------------- Pr?xima Parte ----------
Um anexo em HTML foi limpo...
URL: <http://mail.pm.org/pipermail/saopaulo-pm/attachments/20110503/50dfd0f9/attachment.html>


More information about the SaoPaulo-pm mailing list