#!/usr/bin/perl use utf8; use strict; use warnings; use IO::Select; use Data::Dumper; use IO::Socket::INET; # Non-blocking I/O concept. use constant TRUE => scalar 1; use constant ARGUMENTS => scalar 1; use constant NICKNAME => scalar 12; use constant MAXBYTES => scalar 15; # flush memory after every initialization $| = 1; my $info = $ARGV[0]; # User message IP:PORT; my $error = "ERROR"; my $newline = "\n"; my %hash = (); # global variable my @clients = (); my ( $client_data , $server_sock , $sock , $new_sock , $trans , $readable_handles , $port , $kidpid , $data , $msg , $string); if (@ARGV > ARGUMENTS) { print "\nPlease no more than ".ARGUMENTS." argument input!\n"; print "\nCorrect Syntax: perl $0 IP:PORT (e.g. 127.0.0.1:5000)\n"; exit(); } elsif (@ARGV < ARGUMENTS) { print "\nPlease no less than ".ARGUMENTS." argument input!\n"; print "\nCorrect Syntax: perl $0 IP:PORT (e.g. 127.0.0.1:5000)\n"; exit(); } else { my $string = index($info, ':'); if ($string == '-1') { die "Please include ':' in your input - ".$info."\n"; } my @input = split( ':' , $info ); $server_sock = new IO::Socket::INET( LocalAddr => $input[0], LocalPort => $input[1], Proto => 'tcp', Listen => SOMAXCONN, Reuse => 1 ) or die "Could not connect: $!"; print "\n[Server $0 accepting clients at PORT: ".$input[1]." and IP: ".$input[0]."]\n"; $readable_handles = new IO::Select(); $readable_handles->add($server_sock); while (TRUE) { (my $new_readable) = IO::Select->select($readable_handles, undef, undef, 0); # conver string to array @$new_readable foreach $sock (@$new_readable) { # Check if sock is the same with server (e.g. 5000) # if same (new client) accept client socket # else read from socket input if ($sock == $server_sock) { $new_sock = $sock->accept() or die sprintf "ERROR (%d)(%s)(%d)(%s)", $!,$!,$^E,$^E; $readable_handles->add($new_sock); $trans = "Hello version"; $client_data = &send($trans,$new_sock); print "First send: ".$client_data."\n"; } else { $port = $sock->peerport(); print "This is \$sock: ".$sock."\n"; print "This is \$port: ".$port."\n"; $msg = receive($sock); print "First receive: ".$msg."\n"; my @text = split(/ / , $msg , 2); # LIMIT = 2 Only the first two gaps split print Dumper(\@text); if ($text[0] eq "NICK") { if (length($text[1]) > NICKNAME) { $trans = "".$error." Please no more than ".NICKNAME." characters as nickname!"; $client_data = &send($trans,$sock); $readable_handles->remove($sock); close($sock); } elsif ($text[1] =~ s/\W//g) { $trans = "".$error." Special characters detected in the nickname, please remove them!"; $client_data = &send($trans,$sock); $readable_handles->remove($sock); close($sock); } else { $hash{$port}=$text[1]; $trans = "OK"; $client_data = &send($trans,$sock); print "Second send: ".$client_data."\n"; } } # End of if ($text[0] eq "NICK") elsif ($text[0] eq "MSG") { if (length($text[1]) > MAXBYTES) { $trans = "".$error." Please remember that message limit is ".MAXBYTES." bytes, this is the rest of the segmented message: ".$text[1].""; $client_data = &send($trans,$sock); print "In case of message over ".MAXBYTES." send: ".$client_data."\n"; } else { # Get all client(s) socket(s) my @sockets = $readable_handles->can_write(); # Send the same message to client(s) print Dumper(\%hash); foreach my $sck (@sockets) { my $final = "".$text[0]." ".$hash{$port}." '".$text[1]."'"; &send($final,$sck); #print STDOUT "The following data send to Client(s): (\ ".$final." \)\n"; } # End of foreach } } # End of elsif ($text[0] eq "MSG") else { print "Closing client '".$hash{$port}."'!\n"; # when the client disconnects delete $hash{$port}; $readable_handles->remove($sock); close($sock); } # End of else condition } # End of else condition ($sock == $server_sock) } # End of foreach new sock } # End of While (1) print "Terminating Server\n"; close $server_sock; getc(); } # End of else @ARGV sub send { chomp($_[0]); $_[0] = "".$_[0]."".$newline.""; utf8::encode($_[0]); $_[1]->send($_[0]); chomp ($_[0]); #print "The following data send to Cliets: (\ ".$_[0]." \)\n"; return $_[0]; } sub receive { my @array = (); $_[0]->recv($data , MAXBYTES); print "Length of received: ".length($data)."\n"; utf8::decode($data); chomp ($data); # In case of terminating message Client will send Client request MSG (exit or quit) but we can use only the Client part if ($data !~ /^MSG|NICK|Client/i) { $data = "MSG " . "Segmended message: " . "".$data.""; } if($data =~ /^$/) { print "Data packet received empty!\n"; print "From host: ".$_[0]->peerhost()." and port: ".$_[0]->peerport()."\n"; $data = "MSG Server received empty packet from ".$_[0]->peerhost."!"; return $data; } elsif ($data !~ /^$/) { #print STDOUT "The following data received from Client: (\ ".$data." \)\n"; #print "From host: ".$sock->peerhost()." and port: ".$sock->peerport()."\n"; return $data; } else { $error = "".$error."".$newline.""; utf8::encode ($error); $server_sock->send($error); print "Invalid client: ".$new_sock->peerhost()." terminating!\n"; $readable_handles->remove($sock); close($sock); } } #### #!/usr/bin/perl use utf8; use strict; use warnings; use Data::Dumper; use IO::Socket::INET; use constant ARGUMENTS => scalar 2; use constant NICKNAME => scalar 12; use constant MAXBYTES => scalar 255; use constant MAX_PORT => scalar 65536; use constant MIN_PORT => scalar 1; # flush memory after every initialization $| = 1; my $info = $ARGV[0]; # User message argv[0] my $Nickname = $ARGV[1]; # User nickname argv[1] my ( $kidpid, $line , $client_sock , $data , $send ); my $error = 'ERROR'; my $newline = "\n"; if (@ARGV > ARGUMENTS) { print "\nPlease no more than ".ARGUMENTS." arguments (ARGV[])!\n"; print "\nCorrect Syntax: perl $0 'IP:PORT NICKNAME' (e.g. 127.0.0.1:5000 Thanos)\n\n"; exit(); } elsif (@ARGV < ARGUMENTS) { print "\nPlease no less than ".ARGUMENTS." arguments (ARGV[])\n"; print "\nCorrect Syntax: perl $0 'IP:PORT NICKNAME' (e.g. 127.0.0.1:5000 Thanos)\n\n"; exit(); } else { my $string = index($info, ':'); if ($string == '-1') { die "Please add ':' in your input - ".$info."\n"; } my @input = split( ':' , $info ); if ( ($input[1] > MAX_PORT) || ($input[1] < MIN_PORT) ) { print "\nPlease use port number between ".MIN_PORT." - ".MAX_PORT."\n\n"; exit(); } # create a tcp connection to the specified host and port $client_sock = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $input[0], PeerPort => $input[1] ) or die "Can't connect to port ".$input[1]." at ".$input[0].": $!\n"; $client_sock->autoflush(1); # so output gets there right away print STDERR "[Connected to ".$input[0].":".$input[1]."]\n"; #$line = <$client_sock>; my $receive_msg = receive(); if ($receive_msg eq "Hello version") { $Nickname = "NICK ".$Nickname.""; $send = &send($Nickname); $receive_msg = receive(); if ($receive_msg eq "OK") { # split the program into two processes, identical twins die "can't fork: $!" unless defined( $kidpid = fork() ); # the if{} block runs only in the parent process if ($kidpid) { # copy the socket to standard output while ( defined( $receive_msg = receive() ) ) { print "Third receive: ".$receive_msg."\n"; print "Client '".$ARGV[1]."' enter your text here:\n"; } # End of While reading (parent) } # End of if (parent) # the else{} block runs only in the child process else { print "Please note that maximum characters are ".MAXBYTES."\n"; print "Client '".$ARGV[1]."' enter your text here:\n"; # copy standard input to the socket while ( defined( chomp($line = ) ) ) { my $line = "MSG ".$line.""; if ($line =~ /quit|exit/i) { $line = "Client request ".$line.""; print "".$line."\n"; my $send = &send($line); kill( "TERM", $kidpid ); # send SIGTERM to child } $send = &send($line); } # End of read and send } # End of else child } # End of if (OK) else { print "Did not Receive OK!\n"; exit(); } } # End of if (Hello version) else { print "Did not receive Hello version!\n"; exit(); } } # End of else @ARGV sub send { chomp($_[0]); $_[0] = "".$_[0]."".$newline.""; utf8::encode($_[0]); $client_sock->send($_[0]); chomp($_[0]); #print "The following data send to Server: (\ ".$_[0]." \)\n"; return $_[0]; } sub receive { # we can read from socket through recv() in IO::Socket::INET $client_sock->recv($data , MAXBYTES); utf8::decode($data); chomp($data); #print STDOUT "The following data received form Server: (\ ".$_[0]." \)\n"; return $data; }