2014-09-29 19 views
5

Próbuję napisać jakiś podstawowy system czatu tylko po to, aby nauczyć się perla. Próbuję wprowadzić chatlog do pliku 1 i wydrukować nową wiadomość, jeśli jest ona widoczna w pliku chatlog.dat, więc napisałem funkcję, która robi prawie to samo, ale mam pewne problemy i nie wiem, jak rozwiązać im. Teraz mam 2 problemy!Podstawowy system czatowy na perlu pod Linuksem

  1. nie mogłem zrozumieć, jak zachować checkFile funkcja zawsze aktywna (np multiprocession) do ciągłego sprawdzania nowych wiadomości

  2. Ten problem występuje, gdy próbuję napisać nową wiadomość, która będzie dołączana do czatu. Tłumacz czeka na moje wejście na linię my $newMessage = <STDIN>;, ale co jeśli ktoś napisze nową wiadomość? nie będzie pokazane, dopóki nie wciśnie enter ... jak to unieważnić?

    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

To co 'pętle select' są przeznaczone. Ułatwione używanie IO :: Select, ale wciąż niezwykle skomplikowane. Prostsze korzystanie z wątków. – ikegami

+0

Tworzysz także rodzaj wyścigu - jeśli wyślesz dwie wiadomości w krótkich odstępach czasu, wydrukujesz tylko drugą. – Sobrique

+0

@Sobrique tak, to jest trzeci problem, ale nie ma wysokiego priorytetu JESZCZE, przynajmniej mogę dodać opcję czasu do czatu, aby nowo wydrukowane wiadomości miały inny czas, dlatego będzie to uważane za NOWY komunikat – PYPL

Odpowiedz

0

Odpowiadając na moje własne pytanie

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! Nie rób tego. Zajęta pętla oczekiwania to straszna rzecz. Spowoduje to zjedzenie całego IO i procesora, który ma do zaoferowania twoje pudełko, ponieważ ponownie uruchamia 'cat' tak szybko, jak tylko może. Przynajmniej umieść tam "sleep 1;". – Sobrique

1

pierwsze:

  • nie używać echo wewnątrz skryptu Perl. To paskudne, że można uciec, gdy masz doskonale dobre procedury IO.

  • Używanie cat do odczytu plików jest tak samo nieprzyjemne jak użycie "echo".

  • czytanie <STDIN> jak to będzie połączenie blokujące - co oznacza, że ​​twój skrypt się zatrzyma.

  • ale to nie jest tak źle, jak się wydaje, ponieważ w przeciwnym razie uruchamiasz pętlę "zajętości oczekiwania", która będzie powtarzać plik cat. To bardzo zły pomysł.

  • Zakładasz, że pisanie takiego pliku jest operacją atomową, kiedy nie jest. Będziesz także miał problemy z robieniem tego.

Co proponuję zrobić to spojrzeć na IO::Handle a także rozważyć użycie flock aby upewnić się, że masz plik zamknięty dla IO. Możesz również rozważyć opcję File::Tail.

Proponuję jednak, aby wziąć pod uwagę inny tryb IPC - ponieważ "wymiana plików" jest dość nieefektywna. Jeśli naprawdę chcesz użyć systemu plików dla swojego zamówienia reklamowego, możesz rozważyć użycie potoku FIFO - każdy "klient" powinien otworzyć swój własny i mieć serwer odczytywany i łączący go.

Tak czy inaczej - będziesz musiał użyć IO::Select lub wielowątkowości, aby zamienić między czytaniem a pisaniem. http://perldoc.perl.org/IO/Select.html

+1

IO :: Select nie będzie działał z File :: Tail, ponieważ File :: Tail nie udostępnia uchwytu pliku systemowego, ale "wirtualnego", znanego tylko Perlowi. – ikegami

+0

Ah, punkt - myślałem bardziej w kategoriach używania 'can_read' w' STDIN'. – Sobrique

+0

Zamierzam zmodyfikować główny kod na podstawie twojej opinii, dziękuję – PYPL

Powiązane problemy