Appendix B. Perl Error Codes and Special Variables


 
Network Programming with Perl
By Lincoln  D.  Stein
Slots : 1
Table of Contents
Appendix A.   Additonal Source Code

    Content

mchat_client.pl (Chapter 21)

The mchat_client.pl script implements the client side of the multicast chat system developed in Chapter 21.

 0   #!/usr/bin/perl -w   1   # file: chat_client.pl   2   # chat client using UDP   3   use strict;   4   use IO::Socket;   5   use IO::Select;   6   use ChatObjects::ChatCodes;   7   use ChatObjects::MComm;   8   use IO::Socket::Multicast;   9   use Sys::Hostname;     10   $SIG{INT} = $SIG{TERM} = sub { exit 0 };  11   my ($nickname,$comm,$mcomm);    12   # dispatch table for commands from the user  13   my %COMMANDS = (  14                   channels  => sub { $comm->send_event(LIST_CHANNELS)      },  15                   join      => sub { $comm->send_event(JOIN_REQ,shift)     },  16                   part      => sub { $comm->send_event(PART_REQ,shift)     },  17                   users     => sub { $comm->send_event(LIST_USERS)         },  18                   public    => sub { $comm->send_event(SEND_PUBLIC,shift)  },  19                   private   => sub { $comm->send_event(SEND_PRIVATE,shift) },  20                   login     => sub { $nickname = do_login()      },  21                   quit      => sub { undef },  22                  );    23   # dispatch table for messages from the server  24   my %MESSAGES = (  25                   ERROR()          => \&error,  26                   LOGIN_ACK()      => \&login_ack,  27                   JOIN_ACK()       => \&join_part,  28                   PART_ACK()       => \&join_part,  29                   PUBLIC_MSG()     => \&public_msg,  30                   PRIVATE_MSG()    => \&private_msg,  31                   USER_JOINS()     => \&user_join_part,  32                   USER_PARTS()     => $user_join_part,  33                   CHANNEL_ITEM()   => \&list_channel,  34                   USER_ITEM()      => \&list_user,  35                   SET_MCAST_PORT() => \&create_msocket,  36                  );    37   # Create and initialize the UDP socket  38   my $servaddr    = shift  'localhost';  39   my $servport    = shift  2027;  40   my $mcast_port  = shift  2028;    41   # create comm object for communicating with chat server  42   $comm = ChatObjects::Comm->new(PeerAddr => "$servaddr:$servport") or die $@;    43   # Try to log in  44   $nickname = do_login();  45   die "Can't log in.\n" unless $nickname;    46   # Read commands from the user and messages from the server  47   my $select = IO::Select->new($comm->socket,\*STDIN);  48   LOOP:  49   while (1) {  50     my @ready = $select->can_read;  51     foreach (@ready) {  52       if ($_ eq $STDIN) {  53         do_user(\*STDIN)  last LOOP;  54       } else {  55         do_server($_);  56       }  57     }  58   }    59   #create multicast socket in response to SET_MCAST_PORT event  60   sub create_msocket {  61     my ($code,$port) = @_;  62     return unless $port =~ /^\d+$/;  63     $select->remove($mcomm->socket) if defined $mcomm;    64     # create multicast comm object for receiving multicast channel messages  65     $mcomm=ChatObjects::MComm->new($port) or die $@;  66     $select->add($mcomm->socket);  67   }  68  # called to handle a command from the user  69  sub do_user {  70    my $h = shift;  71    my $data;  72    return   unless sysread($h,$data,1024);  # longest line  73    return 1 unless $data =~ /\S+/;  74    chomp($data);  75    my($command,$args) = $data =~ m!^/(\S+)\s*(.*)!;  76    ($command,$args) = ('public',$data) unless $command;  77    my $sub = $COMMANDS{lc $command};  78    return warn "$command: unknown command\n" unless $sub;  79    return $sub->($args);  80  }    81  # called to handle a message from the server  82  sub do_server {  83    die "invalid socket" unless my $s = ChatObjects::Comm->sock2comm(shift);  84    die "can't receive: $!" unless  85      my ($mess,$args) = $s->recv_event;  86    my $sub = $MESSAGES{$mess}  return warn "$mess: unknown message from server\n";  87    $sub->($mess,$args);  88    return $mess;  89  }    90  # try to log in (repeatedly)  91  sub do_login {  92    $comm->send_event(LOGOFF,$nickname) if $nickname;  93    my $nick = get_nickname();  # read from user  94    my $select = IO::Select->new($comm->socket);    95    for (my $count=1; $count <= 5; $count++) {  96      warn "trying to log in ($count)...\n";  97      $comm->send_event(LOGIN_REQ,$nick);  98      next unless $select->can_read(6);  99      return $nick if do_server($comm->socket) == LOGIN_ACK; 100     $nick = get_nickname(); 101    } 102  } 103  # prompt user for his nickname 104  sub get_nickname { 105    while (1) { 106      local $ = 1; 107      print "Your nickname: "; 108      last unless defined(my $nick = <STDIN>); 109      chomp($nick); 110      return $nick if $nick =~ /^\S+$/; 111      warn "Invalid nickname.  Must contain no spaces.\n"; 112    } 113  } 114  # handle an error message from server 115  sub error { 116    my ($code,$args) = @_; 117    print "\t** ERROR: $args **\n"; 118  } 119  # handle login acknowledgment from server 120  sub login_ack { 121    my ($code,$nickname) = @_; 122    print "\tLog in successful. Welcome $nickname.\n"; 123  } 124  # handle channel join/part messages from server 125  sub join_part { 126    my ($code,$msg) = @_; 127    my ($title,$users,$mcast_addr) = $msg =~ /^(\S+) (\d+) ([\d.]+)/; 128    if ($code == JOIN_ACK) { 129      # add multicast address to the list that we receive 130      $mcomm->socket->mcast_add($mcast_addr); 131      print "\tWelcome to the $title Channel ($users users)\n"; 132    } else { 133      $mcomm->socket->mcast_drop($mcast_addr); 134      print "\tYou have left the $title Channel\n"; 135    } 136  } 137  # handle channel listing messages from server 138  sub list_channel { 139    my ($code,$msg) = @_; 140    my ($title,$count,$mcast_addr,$description) = $msg =~ /^(\S+) (\d+) ([\d.]+) (.+)/; 141    printf "\t%-20s %-40s %3d users\n","[$title]",$description,$count; 142  } 143  # handle a public message from server 144  sub public_msg { 145    my ($code,$msg) = @_; 146    my ($channel,$user,$text) = $msg =~ /^(\S+) (\S+) (.*)/; 147    print "\t$user [$channel]: $text\n"; 148  } 149  # handle a private message from server 150  sub private_msg { 151    my ($code,$msg) = @_; 152    my ($user,$text) = $msg =~ /^(\S+) (.*)/; 153    print "\t$user [**private**]: $text\n"; 154  } 155  # handle user join/part messages from server 156  sub user_join_part { 157    my ($code,$msg) = @_; 158    my $verb = $code == USER_JOINS ? 'has entered' : 'has left'; 159    my ($channel,$user) = $msg =~ /^(\S+) (\S+)/; 160    print "\t<$user $verb $channel>\n"; 161  } 162  # handle user listing messages from server 163  sub list_user { 164    my ($code,$msg) = @_; 165    my ($user,$timeon,$channels) = $msg =~ /^(\S+) (\d+) (.+)/; 166    my ($hrs,$min,$sec) = format_time($timeon); 167    printf "\t%-15s (on %02d:%02d:%02d) Channels: %s\n",$user,$hrs,$min,$sec,$channels; 168  } 169  # nicely formatted time (hr, min sec) 170  sub format time { 171    my $sec = shift; 172    my $hours = int( $sec/(60*60) ); 173    $sec     -= ($hours*60*60); 174    my $min   = int( $sec/60 ); 175    $sec     -= ($min*60); 176    return ($hours,$min,$sec); 177  } 178  END { 179    if (defined $comm) { 180      $comm->send_event(LOGOFF,$nickname); 181      $comm->close; 182    } 183  } 

   
Top


Network Programming with Perl
Network Programming with Perl
ISBN: 0201615711
EAN: 2147483647
Year: 2000
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net