#! /usr/bin/env perl use warnings; use strict; use utf8; use feature qw; use IO::Socket::INET; use IO::Select; use Getopt::Long; sub box_string { my ($str) = @_; my $line = "|--".'-' x length($str)."--|"; say $line; say "|->", $str, "<-|"; say $line; } GetOptions ( "Port|P=i" => \my $port, "Addr|A=s" => \my $addr ) || die "Invalid command line '$!'"; do { say "Must call $0 --Port|P=1234 --Addr|A=127.0.0.1"; exit (1); } unless $port && $addr; box_string("Server on: $addr:($port)"); print "Start server(y/n)? "; do { say "Exiting $0"; exit (0); } unless =~ /^y$/; my $socket = IO::Socket::INET->new( LocalAddr => $addr, LocalPort => $port, Listen => 5, Proto => 'tcp', ReuseAddr => SO_REUSEADDR ) || die "Invalid socket '$!'"; box_string("Server active on: $addr:($port)"); say "Server running...."; my $sel = IO::Select->new; $sel->add([$socket, "Server Socket"]); my @read_handles; my @write_handles; while (@read_handles = $sel->can_read) { for my $handle (@read_handles) { if ($handle->[0] == $socket) { $sel->add([scalar($socket->accept), "Client Socket"]); say "Accepted new client"; }else { @write_handles = grep { ($_->[0] != $socket) && ($_->[0] != $handle->[0]) } $sel->can_write(0); do { say "Connection problems with ", $handle->[1], " exiting"; do { print {$_->[0]} "Client: ", $handle->[1], " exited\r\n"; print {$_->[0]} "<>\r\n"; } for @write_handles; $sel->remove($handle->[0]); $handle->[0]->close; next; } if $handle->[0]->eof; my $msg = do { local $/ = "\r\n"; my $h = $handle->[0]; chomp(my $m = <$h>); $m; }; if ($msg =~ /h-/) { print {$handle->[0]} "h- display help message\r\n"; print {$handle->[0]} "m-(Message) send message\r\n"; print {$handle->[0]} "l- list users\r\n"; print {$handle->[0]} "t-(UserName) change user name\r\n"; print {$handle->[0]} "x- exit\r\n"; print {$handle->[0]} "<>\r\n"; }elsif ($msg =~ /m-/) { say "Client: ", $handle->[1], " sent:$msg"; do { print {$_->[0]} "Client: ", $handle->[1], " sent:$msg\r\n"; print {$_->[0]} "<>\r\n"; } for @write_handles; }elsif ($msg =~ /l-/) { say "Client: ", $handle->[1], " user listing"; do { print {$handle->[0]} "Client: ", $_->[1], "\r\n"; } for @write_handles; print {$handle->[0]} "<>\r\n"; }elsif ($msg =~ /t-/) { $handle->[1] = $msg; say "Client: ", $handle->[1], " changed names"; do { print {$_->[0]} "Client: ", $handle->[1], " changed names\r\n"; print {$_->[0]} "<>\r\n"; } for @write_handles; }elsif ($msg =~ /x-/) { say "Client: ", $handle->[1], " exited"; do { print {$_->[0]} "Client: ", $handle->[1], " exited\r\n"; print {$_->[0]} "<>\r\n"; } for @write_handles; $sel->remove($handle->[0]); $handle->[0]->close; }else { say "Client: ", $handle->[1], " sent unknown msg: $msg"; } } } } $socket->close; exit(0); ###client #! /usr/bin/env perl use warnings; use strict; use utf8; use feature qw; use IO::Socket::INET; use IO::Select; use Getopt::Long; sub box_string { my ($str) = @_; my $line = "|--".'-' x length($str)."--|"; say $line; say "|->", $str, "<-|"; say $line; } GetOptions ( "Port|P=i" => \my $port, "Addr|A=s" => \my $addr, "User|U=s" => \my $user ) || die "Invalid command line '$!'"; do { say "Must call $0 --Port|P=1234 --Addr|A=127.0.0.1 --User|U=UserName"; exit (1); } unless $port && $addr && $user; box_string("Client($user) on: $addr:($port)"); print "Start client(y/n)? "; do { say "Exiting $0"; exit (0); } unless =~ /^y$/; my $client = IO::Socket::INET->new( PeerAddr => $addr, PeerPort => $port, Proto => 'tcp' ) || die "Invalid client '$!'"; box_string("Client($user) active on: $addr:($port)"); say "Client running...."; my $sel = IO::Select->new; $sel->add(\*STDIN); $sel->add($client); print {$client} "t-$user\r\n"; my @read_handles; while (@read_handles = $sel->can_read) { for my $handle (@read_handles) { if ($handle == $client) { do { say "Connection problems... Exiting $0"; exit (3); } if $client->eof; { local $/ = "\r\n"; while (<$client>) { chomp; last if /<>/; print "$_\n"; } } }else { chomp(my $msg = ); do { say "Exiting $0"; print {$client} "$msg\r\n"; exit (0); } if $msg =~ /x-/; print {$client} "$msg\r\n"; } } } $client->close; exit(0);