#!/usr/bin/perl use strict; use warnings; my $port="5678"; my $wait=2; my $service=csharp_ipc_service->new($port,$wait); print csharp_ipc_service::error()."\n" unless($service); # Etwas Demonstartion, dass es Funktioniert if($service->test_running()) { print "test_running() erfolgreich\n"; } else { print "ERROR:".$service->error()."\n"; } print "#"x80,"\n"; if($service->test_running()) { print "test_running() erfolgreich\n"; } else { print "ERROR:".$service->error()."\n"; } print "#"x80,"\n"; my $val=$service->test_get(1); if(defined($val)) { print "test_get(1) = $val\n"; } else { print "ERROR:".$service->error()."\n"; } print "#"x80,"\n"; $val=$service->test_get(4); if(defined($val)) { print "test_get(4) = $val\n"; } else { print "ERROR:".$service->error()."\n"; } print "#"x80,"\n"; ######################################################################## ######################################################################## ######################################################################## {package csharp_ipc_service; use strict; use warnings; use RPC::XML; use RPC::XML::Client; use FindBin; use POSIX ":sys_wait_h"; my $ERROR=undef; #----------------------------------------------------------------------- sub new { my $class=shift; my $port=shift; my $wait=shift; my $self={}; $self->{stop}=0; $self->{pid}=0; bless($self, $class); unless($self->_start($port,$wait)) { $ERROR=$self->{ERROR}; return undef; } return $self; } #----------------------------------------------------------------------- # Kommandos, die auf dem Server ausgeführt werden sollen sub test_running { my $self=shift; my $ret=$self->_runn_cmd('test.Running'); return 1 if(defined($ret)); return 0; } sub test_get { my $self=shift; my $number=shift; return $self->_runn_cmd('test.Get',$number); } #----------------------------------------------------------------------- # Fehler ausgeben wenn sie auftreten sub error { my $self=shift; if($self && ref($self) eq __PACKAGE__) { my $err=$self->{ERROR} || ''; $self->{ERROR}=undef if($self->{ERROR}); return $err; } else { my $err=$ERROR; $ERROR=undef; return $err; } } ######################################################################## # privat # ######################################################################## sub _add_error { my $self=shift; my $msg=shift; if($msg) { if($self->{ERROR}) { $self->{ERROR}.="\n$msg"; } else { $self->{ERROR}=$msg; } } } sub _runn_cmd { my $self=shift; my $resp=$self->{ipc}->send_request(@_); if(ref($resp) && ref($resp) ne 'RPC::XML::fault') { return $resp->value(); } else { if(ref($resp)) { $self->_add_error($resp->string()); } else { $self->_add_error("no server connection ($!)"); } } return undef; } sub _sig_child { my $self=shift; my $msg=waitpid($self->{pid},0); $self->_add_error("server died unexpected") unless($self->{stop}); } sub _start { my $self=shift; my $port=shift || 5678; my $wait=shift || 5; unless($self->{pid}) { $self->{stop}=0; $self->{pid}=0; $self->{ipc}=undef; local $SIG{CHLD}=sub{ $self->_sig_child(@_); }; # XML-IPC Client initialisieren my $host='http://localhost:'.$port.'/test'; $self->{ipc}=RPC::XML::Client->new($host); # läuft möglicherweise schon ein Service? # wenn ja, keinen eigenen starten. my $resp=$self->{ipc}->send_request('x'); unless(ref($resp)) { #Service starten my $cs_pid=fork(); if(defined($cs_pid)) { if($cs_pid) { $self->{pid}=$cs_pid; # warten dass der Server hochkommt. sleep($wait); } # im Kindprozess C# Programm starten # da müsste man noch etwas machen wenn man auch # den MS-Interpreter nutzen möchte # zudem ist das alles auf linux/Unix abgestimmt # (siehe Pfadangabe) else { # programm starten exec("/usr/bin/mono $FindBin::Bin/mono/xml_rpc_deamon.exe -d -s localhost -p $port"); # wenn man hier ankommt lief was verkehrt! exit(10); } } else # fork hat nicht geklappt! { $self->_add_error("Fork failed"); return 0; } } return 1; } } sub _stop { my $self=shift; if($self->{pid}) { $self->{stop}=1; my $pid=$self->{pid}; local $SIG{CHLD}='DEFAULT'; # zu beenden auffordern kill('KILL',$pid) if(waitpid($pid, WNOHANG)>-1); # maximal 20 Sekunden warten. eval{ local $SIG{ALRM}={die("timeout1\n")}; alarm(20); waitpid($pid,0); alarm(0); }; # 20 Sekunden gewartet ohne dass der Prozess beendet wurde if($@ && waitpid(-1, WNOHANG)>-1) { # Abwürgen kill('TERM',$pid) if(waitpid($pid, WNOHANG)>-1); # und 2 Sekunden warten eval{ local $SIG{ALRM}={die("timeout2\n")}; alarm(5); waitpid($pid,0); alarm(0); }; # Prozess hängt ganz übel # Deadlock ?? if($@ && waitpid(-1, WNOHANG)>-1) { $SIG{CHLD}='IGNORE'; die("Can't kill $pid!\n"); } } } } sub DESTROY { _stop(@_); } 1;}