2014-09-29 70 views
5

我試圖編寫一些基本的聊天系統來學習perl。我試圖將聊天日誌寫入1個文件並在出現在chatlog.dat文件中時顯示新消息,所以我寫了一個功能幾乎相同的東西,但是我遇到了一些問題並且不知道如何解決他們。 所以現在我有2個問題!linux下基於perl的基本聊天系統

  1. 我不明白如何保持checkFile功能始終處於激活狀態(如multiprocession)到新郵件

  2. 當我試圖寫將追加新的消息出現此問題的連續檢查進入聊天日誌。口譯員等待我的輸入my $newMessage = <STDIN>;,但是,如果有人寫了一條新消息呢?它將不會顯示,直到他按下輸入...如何無效?

    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

那就是'select'循環是。使用IO :: Select更容易,但仍然非常複雜。更簡單的使用線程。 – ikegami 2014-09-29 16:43:33

+0

您也正處於種族競爭狀態 - 如果您連續發送兩封郵件,則只會打印第二封郵件。 – Sobrique 2014-09-29 19:00:02

+0

@Sobrique是啊,這是第三個問題,但它沒有高優先級,至少我可以添加時間選項到聊天日誌,所以新打印的消息會有另一個時間,因此它將被視爲一個新消息 – PYPL 2014-09-29 19:09:40

回答

0

回答我的問題

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!不要這樣做。忙碌的等待循環是一件可怕的事情。它會吃掉你的盒子所提供的所有IO和CPU,因爲它會以儘可能快的速度重新運行「貓」。至少在裏面放一個「睡眠1」。 – Sobrique 2014-10-09 08:39:18

1

第一:

  • 不要在Perl腳本中使用echo。當你有完美的IO例程時,逃脫shell是令人討厭的。

  • 使用cat來讀取文件與使用'echo'一樣討厭。

  • 閱讀<STDIN>這樣就會阻塞呼叫 - 這意味着你的腳本會暫停。

  • 但這並不像聽起來那麼糟糕,因爲否則您正在運行一個「忙碌的等待」循環,這個循環將重複執行cat該文件。這是一個非常糟糕的主意。

  • 你假設寫一個像這樣的文件是一個原子操作,當它不是。你也會遇到問題。

我有什麼建議你做一下IO::Handle,也可以考慮使用flock,以確保你有鎖定IO文件。您也可以考慮使用File::Tail

但是我實際上會建議你想要考慮一種不同的IPC模式 - 因爲'文件交換'效率很低。如果你真的想爲你的IO使用文件系統,你可能需要考慮使用FIFO管道 - 讓每個「客戶端」打開它自己的,並讓服務器讀取併合並它們。

無論哪種方式 - 你要麼需要使用IO::Select或者多線程,只是爲了在讀寫之間來回切換。 http://perldoc.perl.org/IO/Select.html

+1

IO :: Select不能用於File :: Tail,因爲File :: Tail沒有提供系統文件句柄,而是一個只有Perl才知道的「虛擬」句柄。 – ikegami 2014-09-29 19:43:08

+0

啊,公平點 - 我正在考慮在'STDIN'上使用'can_read'。 – Sobrique 2014-09-30 11:18:23

+0

我會根據您的反饋修改主要代碼,謝謝 – PYPL 2014-10-09 07:28:58