#use strict; #require "ipc.ph"; #require "sem.ph"; use IO::Socket; use IO::File; use POSIX ":sys_wait_h"; sub start_log #(Dateiname)  {  my $filename = shift;  open(FH,">>".$filename) || return 0;  chmod($filename,644);  # Autoflush setzen fuer FH  my $oldfh = select(FH); $| = 1; select($oldfh);  # Lock freigeben  flock(FH,8);  # warn und die umleiten  $SIG{} = \&log_warn;  $SIG{} = \&log_die;  return 1;  } sub end_log  {  close(FH);  } sub log_info #(Message)  {  my $time = localtime;  my $mesg = join(' ',@_) || "Oops!";  $mesg = $time . " [INFO] " . $mesg . "\n";  flock(FH,2);  print FH $mesg;  flock(FH,8);  } sub log_warn #(Message)  {  my $time = localtime;  my $mesg = join(' ',@_) || "Oops!";  $mesg = $time . " [ERROR] " . $mesg . "\n";  flock(FH,2);  print FH $mesg;  flock(FH,8);  } sub log_die #(Message)  {  my $time = localtime;  my $mesg = join(' ',@_) || "Oops!";  $mesg = $time . " [FATAL] " . $mesg . "\n";  flock(FH,2);  print FH $mesg;  flock(FH,8);  close(FH);  die @_;  } # Port Nr 7777 wg. Firewall Konfiguration im PDV Labor use constant MYPORT => 7777; # my $sock = ''; my $client = ''; my $pid; my %child_pids = (); # Hash fuer Prozessnummern my %key_ids = (); # Hash fuer shared mem keys my %typedef = (); # Hash fuer typedefs my %sizeof = (); # Hash fuer sizeofs # signal handler sub catcher  {  my $pid;  $SIG{CHLD} = \&catcher;  foreach $pid (keys(%child_pids))    {    if(waitpid($pid, WNOHANG)) # Zombies verhindern      {      print "Terminated: $pid\n";      delete $child_pids{$pid};      }    }  } start_log ("pdvServer.log"); log_info("Server Start"); $SIG{CHLD} = \&catcher; # mit pack/unpack werden die Daten binaer gespeichert/entpackt # typedef und sizeof 'Arbeiten wie in C', wird von perl-Programmierern gehasst! $typedef{SHORT} = 'S'; $typedef{LONG} = 'L'; $typedef{DOUBLE} = 'd'; $sizeof{SHORT} = length(pack($typedef{SHORT},())); $sizeof{LONG} = length(pack($typedef{LONG},())); $sizeof{DOUBLE} = length(pack($typedef{DOUBLE},())); # ##### # Hier geht das Haupt-Programm los # # socket erstellen $sock = new IO::Socket::INET(LocalPort => MYPORT,                             Reuse     => 1,                             Listen    => 20)    or die "can't create local socket: $@\n"; print STDERR "Accepting connections on Port ", MYPORT, "...\n"; # server laeuft in Endlos-Schleife while (1)  {  # wartet auf neue Verbindungen von Clients  $client = $sock->accept();  # accept wird auch von einem signal 'unterbrochen', darum hier noch ne Abfrage  if ($client)    {    # Verbindung ist aufgebaut    print STDERR "Accepted connection from ",        $client->peerhost(), ":", $client->peerport(), "\n";    # Erzeugen eines Kindprozesses.    $pid = fork();    if ($pid == 0) # Kindprozess      {      &serverChild;      exit(0);      }      else # else Eltern-Prozess        {        print STDERR "Prozess $pid started\n ";        $child_pids{$pid} = 1;        $client->close; # not needed in parent      }    }  } # ##### # Kind-Prozess fuer jeden verbundenen Client # sub serverChild { my $id; $sock->close; # not needed in child $ipaddr = inet_aton($client->peerhost()); print $client "Hi ".gethostbyaddr($ipaddr, AF_INET). " nice to meet you ...\n"; while (<$client>)  {  chomp;  log_info($client->peerhost()." sent: $_");    SWITCH:    {    @mycmd=split(' ',$_);    # START Abtastrate Punkte -> UniqueID zurueck;    if ($mycmd[0] =~ /START/i)      {      if ($#mycmd < 2)        {        print $client "NEE usage: START Abtastrate Punkte\n";        }      else        {        $id = time()/$$;        $IPC_PRIVATE = 0;        $IPC_RMID = 0;                # Speicherbedarf        # Punkteanzahl (Long), id (Double), status (Long)        # und die Daten (Short)        #        $size = $mycmd[2] * $sizeof{SHORT} + $sizeof{LONG} + $sizeof{DOUBLE} + $sizeof{LONG};                $key = shmget($IPC_PRIVATE, $size, 0777);        unless ($key)          {          log_info("Could not get shared memory");          print $client "NEE Could not get shared memory\n";          last SWITCH;          }        else          {          log_info("shared mem key START : $key");          # hier 'eigentlich'          # process fork mit vererbung von $key, $id, status 0, Punkteanzahl und Abtastrate          # wenn fertig status auf 1 setzen, das wars ...          #          # hier kann ich nun "einfach" das memory beschreiben .... und beim DATA zurueckgeben                    # 'Header' schreiben          $offset = 0;          shmwrite $key, pack($typedef{LONG},$mycmd[2]),$offset,$sizeof{LONG};          $offset += $sizeof{LONG};          shmwrite $key, pack($typedef{DOUBLE},$id),$offset,$sizeof{DOUBLE};          $offset += $sizeof{DOUBLE};          $status = 0;          $statusOffset = $offset;          shmwrite $key, pack($typedef{LONG},$status),$offset,$sizeof{LONG};          $offset += $sizeof{LONG};                    # dummy Daten sin(x)/x          for($i=0; $i <$mycmd[2]; $i++)            { $test =  sin($i+1)/($i+1) * 2047 + 2048; print "$test\n";            shmwrite $key, pack($typedef{SHORT},sin($i+1)/($i+1) * 2047 + 2048),$offset,$sizeof{SHORT};            $offset += $sizeof{SHORT};            }          $status = 1;          shmwrite $key, pack($typedef{LONG},$status),$statusOffset,$sizeof{LONG};                    $key_ids{$id} = $key;          print $client "OK $id\n"          }        }      last SWITCH;      }    if ($mycmd[0] =~ /DATA/i)      {      if ($#mycmd < 1)        {        print $client "NEE id needed\n";        }      else        {        #wenn in key_ids von id ein key steht mit diesem testen ob status ok und dann mit diesem        #key die daten auslesen und schicken. dann memory loeschen.        $id = $mycmd[1];        $key = $key_ids{$id};        if ($key)          {          log_info("shared mem key DATA : $key");          #          $offset = 0;          shmread $key, $points,$offset,$sizeof{LONG};          $offset += $sizeof{LONG};          $points = unpack($typedef{LONG},$points);          shmread $key, $id,$offset,$sizeof{DOUBLE};          $offset += $sizeof{DOUBLE};          $id = unpack ($typedef{DOUBLE}, $id);          shmread $key, $status,$offset,$sizeof{LONG};          $offset += $sizeof{LONG};          $status = unpack ($typedef{LONG}, $status);            if ($status == 1)            {            print $client "OK $points daten werden gesendet\n";            for($i=0; $i <$points; $i++)              {              shmread $key,$data,$offset,$sizeof{SHORT};              #print $client "offset: $offset;data[$i] = ". unpack ($typedef{SHORT},$data). "\n";              #print $client "offset: $offset;data[$i] = $data \n"; # Auf vielfachen Wunsch des(r) Studenten ...              print $client "$i:$data\n";              $offset += $sizeof{SHORT};              }            print $client "\nOK Done\n";            shmctl($key, $IPC_RMID,0); # loescht shared memory            delete $key_ids{$id};            }          else            {            print $client "NEE buffer not ready\n";            }          }        else          {          print $client "NEE kein key fuer die id gefunden\n";          }        }      last SWITCH;      }    if ($mycmd[0] =~ /STOP/i)      {      print $client "OK not implemented id would be needed\n";      last SWITCH;      }    if ($mycmd[0] =~ /ENDE/i)      {      print $client "OK will end task and close connection\n";      # hier alle shared memory Bereiche zu dem Prozess loeschen.      foreach $key (values(%key_ids))        {        print "Remove: $key\n";        shmctl($key, $IPC_RMID,0);        }      $client->close;      exit(0);      last SWITCH;      }    print $client "NEE unknown command\n";    }  } }