2016-12-12 3 views
1

J'ai un script perl qui a fonctionné comme un «intermédiaire» entre un programme local et un site web interactif externe.Perl, websocket en boucle infinie

Le problème est que le site Web externe a migré de la connexion TCP simple vers une connexion WebSocket. Lorsque le serveur utilisait TCP, après la connexion initiale, le client (le script) et le serveur (site Web externe) passaient par une poignée de main, puis le script envoie le nom d'utilisateur et le mot de passe et le serveur répond finalement avec Ensuite, le script ira dans une boucle infinie et attendra les données des deux connexions, puis traiter ces données et "imprimer" les connexions au besoin.

J'ai pu établir la connexion websocket avec le serveur en utilisant Mojo :: UserAgent ainsi qu'avec protocol :: websocket, passer par la poignée de main et l'échange d'informations (nom d'utilisateur, mot de passe, etc.), mais je n'a pas pu (ou mieux dit: je ne sais pas comment) "jeter" la connexion websocket dans la boucle infinie via IO :: Select (La raison pour laquelle je veux utiliser IO :: Select est que cela nécessitera des changements minimes au script, mais d'autres suggestions sont certainement les bienvenues).

Les parties pertinentes du script sont les suivantes:

# Creating connection for local program 
$lsn=new IO::Socket::INET(
    Proto => 'tcp', 
    LocalPort => 6000, 
    Listen => 1, 
); 
unless(defined $lsn){ 
    print"$0: $!\n"; 
    exit 1; 
} 
print"Waiting for local program connection on port 6000\n"; 
$server=$lsn->accept; 
$lsn->close; 
unless(defined $server){ 
    print "$0: Unable to accept incoming connection: $!\n"; 
    exit 1; 
    } 
# At this point, the script is waiting for a connection from 
# the local program on port 6000 
printf"Connection accepted from %s\n",$server->peerhost; 
select $server; 
binmode $server; 
$stdin=$server; 
(select)->autoflush(1); 
# Creating connection for external website 
$net=new IO::Socket::INET(
    Proto => 'tcp', 
    PeerAddr => $yog, 
    PeerPort => $yserverport, 
); 

unless(defined($net)){ 
    print "Can't connect!\n"; 
    exit 1; 
} 
$net->autoflush(1); 
#################################### 
# Here the script and server will # 
# exchange information few times # 
#################################### 
my $sel=new IO::Select($stdin,$net); 
$net->autoflush(0); 
while (1){ 
    foreach my $i($sel->can_read(0.05)){ 
     if($i==$net){ 
      &dosomething; 
      $net->flush; 
     } 
     else{ 
      &dosomething2; 
      $net->flush; 
     } 
    } 
} 

Les exemples de boucle infinie que j'ai trouvé, ne sont pas appropriés dans ce cas parce que je dois utiliser une boucle infinie qui peut vérifier les données entrantes sur les deux connexions.

Répondre

0

Les WebSockets nécessitent beaucoup plus qu'une simple socket IO. Ils exigent des poignées de main et un encadrement des données. Je passerais en revue le W3C WebSocket API et ensuite regarder en utilisant un module perl (Net::WebSocket::Server) pour faire le levage lourd. En outre, webSockets ne fonctionnera qu'avec le navigateur chrome utilisant SSL, donc si vous êtes intéressé par la compatibilité croisée, utilisez plutôt Net :: WebSocket :: Server avec IO :: Socket :: SSL et voici un exemple de SSL:

#!/usr/bin/perl 
use strict; 
use warnings; 
use IO::Socket::SSL; 
use Net::WebSocket::Server; 

my $ssl_server = IO::Socket::SSL->new(
     Listen  => 5, 
     LocalPort  => 4000, 
     Proto   => 'tcp', 
     SSL_cert_file => '/var/ssl/cert.crt', 
     SSL_key_file => '/var/ssl/cert.key', 
    ) or die "failed to listen: $!"; 

my $port = 6000; 
my $origin = 'https://YOURDOMAIN.com'; 

Net::WebSocket::Server->new(
    listen => $ssl_server, 

    on_connect => sub { 
      our ($serv, $conn) = @_; 
      $conn->on(

      handshake => sub { 
         my ($conn, $handshake) = @_; 
         $conn->disconnect() unless $handshake->req->origin eq $origin; 
        }, 
        utf8 => sub { 

      my ($conn, $msg) = @_; 
      my $MyIP = $conn->ip(); 
      my $MyPORT = $conn->port(); 
      $_->send_utf8($msg) for($serv->connections()); 
       }, 
    ); 
    }, 
)->start; 

Si vous n'êtes pas concernés par Chrome ou SSL est ici un exemple non-SSL de travail, (il faut utiliser stricte et utiliser des avertissements):

#!/usr/bin/perl 

use Net::WebSocket::Server; 

my $port = 6000; 

Net::WebSocket::Server->new(
    listen => $port, 
    on_connect => sub { 
     my ($serv, $conn) = @_; 
     $conn->on(
      utf8 => sub { 
     my ($conn, $msg) = @_; 
       $_->send_utf8($msg) for($serv->connections()); 
      }, 
     ); 
    }, 
)->start; 

de plus, si vous décidez d'utiliser la version SSL, assurez-vous Assurez-vous de mettre à jour votre côté client de ws: // à wss: //

+0

Je devrais mentionner, le script n'est pas appelé par ac script ou programme, le script websocket est en fait son propre "serveur" donc vous l'appelez à partir de la ligne de commande et laissez-le s'exécuter par exemple. "perl myscript.pl" et CTL + C pour annuler. Si vous souhaitez exécuter le script en arrière-plan, vous devez enregistrer le script en tant que service, cela dépend de votre système d'exploitation. Sinon, sur linux au moins, vous pouvez exécuter "perl myscript.pl nohup &" pour exécuter à partir de la ligne de commande et revenir au terminal. J'espère que ça aide. – Bryan