2014-09-29 17 views
5

Sto cercando di scrivere un sistema di chat di base solo per imparare perl. Sto cercando di ottenere il chatlog in un file 1 e di stampare un nuovo messaggio se appare nel file chatlog.dat, quindi ho scritto una funzione che fa quasi la stessa cosa, ma ho alcuni problemi e non so come risolvere loro. Quindi ora ho 2 problemi!sistema di chat di base su perl sotto linux

  1. non riuscivo a capire come mantenere checkFile funzione sempre attiva (come multiprocession) per controllare continuamente di nuovi messaggi

  2. Questo problema si verifica quando sto cercando di scrivere un nuovo messaggio che verrà aggiunto nel chatlog. L'interprete attende il mio intervento sulla linea my $newMessage = <STDIN>;, ma, se qualcuno scrive un nuovo messaggio? non verrà mostrato fino a quando non premerà Invio ... come annullarlo?

    my ($sec,$min,$hour) = localtime(); 
    while(1){ 
        my $userMessage = <STDIN>; 
        last if $userMessage eq "::quit"; 
        `echo "($hour:$min:$sec): $userMessage" >>chatlog.dat`; 
    } 
    
    sub checkFile{ 
        my $lastMessage = ""; 
        my $newMessage = ""; 
        while (1) { 
         my $context = `cat chatlog.dat`; 
         split(/\n/, $context); 
         $newMessage = $_[$#_]; 
         if ($newMessage ne $lastMessage) { 
          print $newMessage; 
          $lastMessage = $newMessage; 
         } 
        } 
    } 
    
+3

Questo è ciò che 'loop select' sono per. Semplificato usando IO :: Select, ma ancora estremamente complicato. Più semplice con i thread. – ikegami

+0

State anche costruendo in una condizione di competizione - se si inviano due messaggi in successione, si stampa solo il secondo. – Sobrique

+0

@Sobrique sì, questo è il terzo problema ma non ha alta priorità ANCORA, almeno posso aggiungere l'opzione tempo nel chatlog in modo che il messaggio appena stampato abbia un'altra volta, quindi sarà considerato come un NUOVO messaggio – PYPL

risposta

0

Rispondendo alla mia domanda

sub checkFile{ 
    my $lastMessage = ""; 
    my $newMessage = ""; 
    my $userName = $_[0]; 
    while (1) { 
     my $context = `cat chatlog.dat`; 
     split(/\n/, $context); 
     $newMessage = $_[$#_]; 
     if ($newMessage ne $lastMessage) { 
      $newMessage =~ /^\(.+\):\((.+)\) (.+$)/; 
      if ($1 ne $userName) { print "[$1]: $2";} 
      $lastMessage = $newMessage; 
     } 
    } 
} 

my $userName = "Rocker"; 
my ($sec,$min,$hour) = localtime(); 
my $thr = threads -> create (\&checkFile, $userName); #Starting a thread to continuously check for the file update 

while (1) { 
    my $userMessage = <STDIN>; #STDIN will not interfere file checking 
    last if $userMessage eq "::quit"; 
    `echo "($hour:$min:$sec):($userName) $userMessage" >>chatlog.dat` if $userMessage =~ /\S+/; 
} 

$thr -> join(); 
+1

Argh! Non farlo. Un ciclo di attesa occupato è una cosa orribile da fare. Mangerà tutto l'IO e la CPU che la tua casella ha da offrire, perché è una sorta di "cat" che procede il più velocemente possibile. Almeno metti un "dormi 1" qui dentro. – Sobrique

1

Primo:

  • non utilizzare echo all'interno di uno script perl. È brutto scappare quando hai perfettamente buone routine IO.

  • utilizzando cat per leggere i file è brutto quanto l'uso di "echo".

  • lettura <STDIN> come se fosse una chiamata bloccante, il che significa che il tuo script si fermerà.

  • ma non è così male come sembra, perché altrimenti si sta eseguendo un ciclo di 'busy busy' che ripeterà il file cat. Questa è una pessima idea.

  • Si presume che scrivere un file come quello sia un'operazione atomica, quando non lo è. Colperai anche i problemi con questo.

Quello che vorrei suggerire di farlo guardare IO::Handle e anche considerare l'utilizzo di flock per assicurare che hai il file bloccato per IO. Potresti anche prendere in considerazione lo File::Tail.

In realtà suggerirei di prendere in considerazione una diversa modalità di IPC, poiché lo scambio di file è piuttosto inefficiente. Se vuoi davvero usare il filesystem per il tuo IO, potresti prendere in considerazione l'uso di una pipe FIFO - far aprire a ciascun "client" il proprio e avere un server che li legge e li unisce.

In entrambi i casi, è necessario utilizzare IO::Select o forse il multithreading, solo per scambiare avanti e indietro tra la lettura e la scrittura. http://perldoc.perl.org/IO/Select.html

+1

IO :: Select non funzionerà con File :: Tail, dal File :: Tail non fornisce un handle di file di sistema ma uno "virtuale" noto solo a Perl. – ikegami

+0

Ah, giusto punto - stavo pensando di più sull'uso di 'can_read' su' STDIN'. – Sobrique

+0

Ho intenzione di modificare il codice principale in base al tuo feedback, grazie – PYPL

Problemi correlati