#!/usr/bin/perl use warnings; use strict; use Glib; use IO::Socket; $|++; my @clients; #used for root messaging to all # a cheap and easy way to prevent zombie children # when the forked child exits # avoids the waitpid stuff,otherwise, the defunct # forked children will wait until the main parent script ends. $SIG{CHLD} = 'IGNORE'; my $num_of_client = -1; my $port = 2345; my $server = new IO::Socket::INET( Timeout => 7200, Proto => "tcp", LocalPort => $port, Reuse => 1, Listen => SOMAXCONN ); print "\n",$server,' ',fileno($server),"\n"; if( ! defined $server){ print "\nERROR: Can't connect to port $port on host: $!\n" ; exit; } else{ print "\nServer up and running on $port\n" } my $main_loop = Glib::MainLoop->new; #my $con_watcher = Gtk2::Helper->add_watch ( fileno( $server ), # 'in', \&callback, $server ); #my $stdin_watcher = Gtk2::Helper->add_watch ( fileno( 'STDIN' ), # 'in', \&watch_stdin, 'STDIN' ); my $con_watcher = Glib::IO->add_watch ( fileno( $server ), 'in', \&callback, $server ); my $stdin_watcher = Glib::IO->add_watch ( fileno( 'STDIN' ), 'in', \&watch_stdin, 'STDIN' ); $main_loop->run; sub watch_stdin { # this is line oriented, # enter as many lines as you want # and you must press Control-d when # finished to send # print "@_\n"; my ($fd, $condition, $fh) = @_; my (@lines) = (); print @lines; foreach my $cli(@clients){ if($cli->connected){ print $cli 'MESSAGE-> ', @lines; }else{ # remove dead client @clients = grep { $_ ne $cli } @clients; } } #always return TRUE to continue the callback return 1; } sub callback{ my ( $fd, $condition, $fh ) = @_; print "callback start $fd, $condition, $fh\n"; #this grabs the incoming connections and forks them off my $client; do { $client = $server->accept } until ( defined($client) ); print "accepted a client, id = ", ++$num_of_client, "\n"; # going into forked handler if ( !fork ) { close($server); #this only closes the copy in the child process # Gtk2::Helper->remove_watch( $con_watcher ); #remove server port watch in child # Gtk2::Helper->remove_watch( $stdin_watcher ); #remove STDIN watch in child Glib::Source->remove( $con_watcher ); #remove server port watch in child Glib::Source->remove( $stdin_watcher ); #remove STDIN watch in child # add a new watch in the forked client my $cli_watcher = Glib::IO->add_watch( fileno( $client ), ['in', 'hup','err'], \&cli_callback, $client); sub cli_callback{ print "\ncli_callback @_\n"; my ( $fd, $condition, $client ) = @_; # since 'in','hup', and 'err' are not mutually exclusive, # they can all come in together, so test for hup/err first if ( $condition >= 'hup' or $condition >= 'err' ) { # End Of File, Hang UP, or ERRor. that means # we're finished. #print "\nhup or err received\n"; #close socket $client->close; $client = undef; # normally return 0 here, # except we need to exit the fork, down below # return 0; #stop callback } # if the client still exists, get data and return 1 to keep callback alive if ($client) { if ( $condition >= 'in' ){ # data available for reading my $bytes = sysread($client,my $data,1024); if ( defined $data ) { # do something useful with the text. print length $data, $data,"\n"; print $client "$data\n"; #echo back } } # the file handle is still open, so return TRUE to # stay installed and be called again. # print "still connected\n"; # possibly have a "connection alive" indicator #print "still alive\n"; return 1; } else { # we're finished with this job. start another one, # if there are any, and uninstall ourselves. print "child exiting\n"; #return 0; #exit instead exit; #since this is forked, we exit } } #end of client callback } #end of forked code else { push @clients, $client; #save clients for root message # back to parent, close client that's been forked #print "\nin parent closed forked client $client\n"; #close($client); # this only closes the copy in the parent process, # assume the parent no longer need talk to the client } return 1; # keep the main port watching callback alive } __END__