PYPL
PYPL

Reputation: 1849

basic chat system on perl under linux

Im trying to write some basic chat system just to learn perl. Im trying to get the chatlog into a 1 file and print new message if it's appears in the chatlog.dat file, So i've wrote a function that does almost the same thing, but I have got some problems and don't know how to solve them. So now I have 2 problems!

  1. I could not understand how to keep checkFile function always active (like multiprocession) to continuously check for new messages

  2. This problem occurs when I'm trying to write a new message that will be appended into the chatlog. The Interpreter waits for my input on the line my $newMessage = <STDIN>;, but, what if someone writes a new message? it will not be shown until he press enter... how to void that?

    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;
            }
        }
    }
    

Upvotes: 5

Views: 258

Answers (2)

PYPL
PYPL

Reputation: 1849

Answering my own question

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();

Upvotes: 0

Sobrique
Sobrique

Reputation: 53488

First:

  • don't use echo within a perl script. It's nasty to shell escape when you've got perfectly good IO routines.

  • using cat to read files is about as nasty as using 'echo'.

  • reading <STDIN> like that will be a blocking call - which means your script will pause.

  • but that's not as bad as it sounds, because otherwise you're running a 'busy wait' loop which'll repeatedy cat the file. This is a very bad idea.

  • You're assuming writing a file like that is an atomic operation, when it's not. You'll hit problems with doing that too.

What I would suggest you do it look at IO::Handle and also consider using flock to ensure you've got the file locked for IO. You may also wish to consider File::Tail instead.

I would actually suggest though, you want to consider a different mode of IPC - as 'file swapping' is quite inefficient. If you really want to use the filesystem for your IO, you might want to consider using a FIFO pipe - have each 'client' open it's own, and have a server reading and coalescing them.

Either way though - you'll either need to use IO::Select or perhaps multithreading, just to swap back and forth between reading and writing. http://perldoc.perl.org/IO/Select.html

Upvotes: 1

Related Questions