Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]4411[/thread]

Wie man am Besten einen Daemon schreibt

Leser: 3


<< |< 1 2 >| >> 13 Einträge, 2 Seiten
cala.vera
 2006-03-09 11:20
#37171 #37171
User since
2006-03-09
7 Artikel
BenutzerIn
[default_avatar]
Hallo,

zunächst will ich sagen, dass ich hier keine Syntax oder sonstigen semantischen Schnick-Schnack diskutieren will :)

Ich arbeite an einem Projekt, welches über Netzwerk kommuniziert.
Meine Frage bezieht sich eher auf die Art, wie man so etwas am Besten entwickelt.

Auf einer Machine läuft ein Daemon, dieser Daemon wartet ständig auf eine Anfrage aus dem Netzwerk. Kommt etwas, arbeitet der Daemon etwas ab und schickt etwas zurück. Was das im Detail ist, ist nicht so wichtig.

Folgendes:
Dieser Daemon existiert bereits hat aber ein Problem: Nach einer gewissen Zeit (ein paar Tage) wird er langsam. Nach etwas mehr Zeit reagiert er dann gar nicht mehr. (Der Prozess selbst läuft noch)

Er arbeitet auf folgende Weise:
1. startet iThread
Code: (dl )
1
2
my $thr = threads->create("receive");
$thr->detach();

dieser öffnet (in einer endlosschleife) eine socket und hört ständig auf sie .
Code: (dl )
1
2
3
while(<$new_sock>) {
$msg=$_;
}

Wenn etwas kommt, schreibt er etwas dementsprechendes in ein Array namens Buffer rein, schließt dann die socket und rennt erneut seine Schleife durch. Dieses Array wird von allen Threads geshared. (threads::shared).

2. Der eigentliche Prozess rödelt ebenfalls ständig eine Endlosschleife durch.
Code: (dl )
1
2
3
4
5
6
if(@BUFFER > 0){
# do something
open socket
sending something
close socket
}


Der Code ist gut lesbar dokumentiert und ich weiß ja auch, was der Daemon macht, allerdings habe ich große Probleme mit der Wartung, da ich einfach nicht weiß, warum er langsam wird und dann irgendwann stehen bleibt :/

Ich hoffe ihr könnt mir helfen. Ich habe zwar diverse Tutorials gefunden, wie man Daemons, Sockets, IThreads implementiert, aber nie etwas alles in einem :)

Warum iThreads ? Tjo ... (die sind eben neu und erst ab 5.8.0 verfügbar). Aber bevor ich jetzt versuche daran zu bohren, würde ich gern wissen, ob das Konzept generell so ist, wie man Net-Daemons schreiben sollte.

Ich wäre für Hilfe gern Dankbar und vielen Dank im Vorraus :)

MfG, Clemens
Taulmarill
 2006-03-09 11:47
#37172 #37172
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
hm, ich benutze threads in Perl nur sehr ungerne. du könntest dir mal POE anschauen, da gibt's auch gleich einige beispiele, wie man kleine server schreibt. http://poe.perl.org/
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
cala.vera
 2006-03-09 12:25
#37173 #37173
User since
2006-03-09
7 Artikel
BenutzerIn
[default_avatar]
Hi,

danke für die schnelle Antwort. Aber ich glaube dass ich schon bei iThreads bleide, sonst kann ich auch gleich den Daemon komplett neu schreiben. Ausserdem arbeite ich mit einem Tool (welches mit dem Daemon kommuniziert) was mit iThreads nur so um sich schmeißt (viel "kriminellere" Sachen) und da habe ich keine Probleme.

Das Problem liegt im Grundkonzept des Daemons. Nur ich habe keine Ahnung wo :/

Mfg, Clemens
Relais
 2006-03-09 12:35
#37174 #37174
User since
2003-08-06
2246 Artikel
ModeratorIn
[Homepage] [default_avatar]
[quote=cala.vera,09.03.2006, 11:25]ich glaube dass ich schon bei iThreads bleibe [...]
Das Problem liegt im Grundkonzept des Daemons. Nur ich habe keine Ahnung wo :/[/quote]
ins blaue geraten könnte das Problem auch ebenso gut bei den Threads liegen.

Ohne Dein Konzept genau zu kennen, kann hier aber keiner mehr sagen, ohne dabei seinen Ruf als ernstzunehmender Ratgeber gleich zu ruinieren.

(meien Daemons laufen ohne Threads und ohne Sorgen...)
Erst denken, dann posten --
27. Deutscher Perl- u. Raku -Workshop (Termin wird noch gesucht) 2025 in München.

Winter is Coming
bloonix
 2006-03-09 12:37
#37175 #37175
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Hallo cala.vera,

Details bzw. Code wäre schon wichtig, um dem Problem auf
die Schliche zu kommen. Ob da Grundlagen weiterhelfen, ist
wirklich sehr fraglich.

Für ein größeres Projekt habe ich auch mal zwei Deamons
(Server & Client) geschrieben, die sich auf auf ettlichen
Maschinen unterhalten.

Grundlegend schreibe ich Deamons wie folgt:

1. while Schleife, in der auf eingehende Frage gewartet wird
2. Objekte, Variablen etc. deklarieren, erzeugen
3. Abfrage auswerten
4. Daten sammeln
5. Daten aufbereiten
6. Daten versenden
7. Objekte, Variablen etc. zerstören

Hattest du dir sowas vorgestellt?

Hast du den Deamon mal beobachtet, wie er sich mit der
Zeit verhält? Zum Beispiel:

1. Speicher Entwicklung
2. Wartezustände
3. Logfiles

Meine Deamons schreiben für jede Aktion eine Meldung mit
Datums- und Zeitstempel, damit ich immer weiß, an welcher
Position im Skript - gedanklich - sich der Deamon
gerade befindet und für welche Aktion er hin und wieder sehr
viel Zeit benötigt. Selbst wenn zwischen zwei aufeinander-
folgenden print-Anweisungen eine Minute Zeit vergeht, kann
man Mutmaßungen anstellen. Diese sehr genaue Logdoku
sollte man aber ausstellen können.

Greez,
opi
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
cala.vera
 2006-03-09 13:43
#37176 #37176
User since
2006-03-09
7 Artikel
BenutzerIn
[default_avatar]
Ok,

hier ist schonmal der Code.
Er macht im Prinzip nix besonderes.
Er wartet auf ein Systemkommando, führt die aus und gibt die Ausgabe zurück.
Ich bin gerade dabei mit Logfiles zu arbeiten, wie ich Speicher Entwicklung und Wartezustände überprüfe weiß ich gar nicht. Gibts da ein paar nette Resouces ?

Das Problem ist, dass er ja sehr lange braucht, bis er irgendwann mal langsam wird bzw. nicht mehr reagiert.\n\n

<!--EDIT|cala.vera|1143039810-->
bloonix
 2006-03-09 14:46
#37177 #37177
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Beim Ausführen mit "use strict;" erhalte ich zunächst folgende
Meldungen ...

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# ./tatdaemon.pl 7070
Global symbol "$ip" requires explicit package name at ./tatdaemon.pl line 81.
Global symbol "$ip" requires explicit package name at ./tatdaemon.pl line 82.
Global symbol "$hersockaddr" requires explicit package name at ./tatdaemon.pl line 96.
Global symbol "$port" requires explicit package name at ./tatdaemon.pl line 97.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 97.
Global symbol "$hersockaddr" requires explicit package name at ./tatdaemon.pl line 97.
Global symbol "$herhostname" requires explicit package name at ./tatdaemon.pl line 98.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 98.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 99.
Global symbol "$hersockaddr" requires explicit package name at ./tatdaemon.pl line 164.
Global symbol "$port" requires explicit package name at ./tatdaemon.pl line 165.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 165.
Global symbol "$hersockaddr" requires explicit package name at ./tatdaemon.pl line 165.
Global symbol "$herhostname" requires explicit package name at ./tatdaemon.pl line 166.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 166.
Global symbol "$iaddr" requires explicit package name at ./tatdaemon.pl line 167.
Global symbol "$wtsocketport" requires explicit package name at ./tatdaemon.pl line 259.
Global symbol "$wtsocketport" requires explicit package name at ./tatdaemon.pl line 260.
Global symbol "$wtsocketport" requires explicit package name at ./tatdaemon.pl line 261.
Global symbol "@enviVars" requires explicit package name at ./tatdaemon.pl line 313.
Global symbol "$envi" requires explicit package name at ./tatdaemon.pl line 316.
Global symbol "@enviVars" requires explicit package name at ./tatdaemon.pl line 316.
Global symbol "$envi" requires explicit package name at ./tatdaemon.pl line 317.
Global symbol "$msg" requires explicit package name at ./tatdaemon.pl line 352.
Global symbol "$msg" requires explicit package name at ./tatdaemon.pl line 353.
Global symbol "$msg" requires explicit package name at ./tatdaemon.pl line 354.
Execution of ./tatdaemon.pl aborted due to compilation errors.


Was zunächst nichts heißen muss, aber sowas mache ich zum
Anfang immer gerne :)

[quote=cala.vera,09.03.2006, 12:43]Ok,
Er macht im Prinzip nix besonderes.[/quote]

Er macht viel unsicheres Zeug, wenn ich das richtig betrachte!

Hierfür gibt es ein Modul. Das ist das schöne an Perl, dass man
in vielen Dingen auf eine Shell verzichten kann. hostname gibt
es auch nur, wenn der PATH gesetzt ist. Statt ...
Code: (dl )
1
2
$Thismachineaddr = `hostname`;
chomp($Thismachineaddr);


... geht es auch so! (man Sys::Hostname)
Code: (dl )
1
2
use Sys::Hostname;
$host = hostname;


Das kannst du nicht wirklich wollen! Oder doch?
Code: (dl )
1
2
3
4
5
6
my $logfile=$PWD.$Thismachineaddr.".log";
open(LOGF, ">$logfile");
...
open STDIN, '/dev/null'   or die "ERROR: Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "ERROR: Can't write to /dev/null: $!";
open STDERR, '>>/dev/null' or die "ERROR: Can't write to /dev/null: $!";


Codeauschnitt aus einem globalen Modul für eine einheitliche
Logfilestruktur... nur ein Beispiel...
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
sysopen(STDOUT,$logfile,O_WRONLY | O_APPEND | O_CREAT) or die $!;
sysopen(STDERR,$global,O_WRONLY | O_APPEND | O_CREAT) or die $!;

# WARNINGS können auch in eine andere, separate Logdatei
# weggeschrieben werden... das bevorzuge ich zum Beispiel.
sysopen(WARN,"$warns",O_WRONLY | O_APPEND | O_CREAT) or die $!;

$SIG{_ _WARN_ _} = \&warnHandler;
$SIG{_ _DIE_ _}  = \&dieHandler;

sub warnHandler {
  print WARN getTime(1), @_;
}

sub dieHandler {
  print STDOUT getTime(1), @_;
  # hier gibt es zwei print's, weil bei mir eine Meldung in eine
  # globale überwachte error-Datei geschrieben wird...
  # die andere ist für das normale Logfile
  print STDERR getTime(1), "$0 ", @_;
  exit(9);
}

sub getTime {
  my $format = shift;
  my @time   = (localtime)[reverse 0..5];
  $time[0] += 1900;
  $time[1]++;

  if (!$format) {
     foreach (@time) { $_ = "0$_" if $_ < 10; }
     return \@time;
  } elsif ($format == 1) {
     return sprintf '%04d-%02d-%02d %02d:%02d:%02d ', @time[0..5];
  } elsif ($format == 2) {
     return sprintf '%04d-%02d-%02d', @time[0..2];
  } elsif ($format == 3) {
     return sprintf '%02d-%02d-%02d', @time[3..5];
  } elsif ($format == 4) {
     return sprintf '%04d-%02d-%02d-%02d:%02d', @time[0..4];
  }
}


Nun kannst du an jeder beliebigen Stelle im Skript Meldungen
rausschreiben, mittels

Code: (dl )
1
2
print getTime(1), "Ich befinde mich gerade hier und mach dies\n";
print getTime(1), "Nun befinde ich mir gerade dort und mache das!\n";


Das ist aber sehr großzügig von dir...
Code: (dl )
1
2
3
4
    elsif(index($msg,"executeshell=") >=0){
...
        chop($cmd);
        $out = execenv($cmd);


Für solche Skripts empfehle ich den Taint-Modus, der zurecht
meckern würde.

Wenn du die Ressourcenentwicklung des Skripts verfolgen
möchtest, dann lohnt ein blick in

Code: (dl )
man 5 proc


speziell

Code: (dl )
1
2
3
/proc/<pid>/statm
# oder etwas formatierter
/proc/<pid>/status


Die Informationen kannst du bei jedem Durchlauf über den
gesamten Zeitraum dokumentieren und im Nachhinein
analysieren. Das da ein paar tausend Zeilen bei rauskommen,
ist vollkommen verständlich und normal. Zum Debuggen sollte
man nicht zu wenig dokumentieren.

Für mehr hat meine Zeit im Moment nicht ausgereicht... ich
versuche heute Abend oder morgen nochmal einen Blick
drauf zu werfen...\n\n

<!--EDIT|opi|1141910351-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
cala.vera
 2006-03-09 15:02
#37178 #37178
User since
2006-03-09
7 Artikel
BenutzerIn
[default_avatar]
Ja,

dann schonmal vielen Dank! Du hast dir ja jetzt schon mehr Arbeit gemacht, als du müsstest :)
Ich werde auf jeden Fall deine Idenn erstmal einfließen lassen.
bloonix
 2006-03-09 15:03
#37179 #37179
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=cala.vera,09.03.2006, 12:43]
Code: (dl )
my $out=`$cmd`;
[/quote]
oops... ganz vergessen...

Wo ist die $? Abfrage?

Was ist, wenn der Prozess unverhofft stirbt oder sonstiges?

Code: (dl )
1
2
3
use IPC::Open2;
#oder
use IPC::Open3;


wäre sicherer, da du mit

Code: (dl )
waitpid($pid,0)


den Prozess wieder einsammeln und STDOUT von STDERR
Meldungen trennen kannst. $? ist auch hier sehr wichtig!\n\n

<!--EDIT|opi|1141909446-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
bloonix
 2006-03-09 15:14
#37180 #37180
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=cala.vera,09.03.2006, 14:02]dann schonmal vielen Dank! Du hast dir ja jetzt schon mehr Arbeit gemacht, als du müsstest :)[/quote]
hey, glaubst du etwa ich mache das umsonst?

ich habe auch irgendwann mal fragen, die auf eine antwort warten ;)\n\n

<!--EDIT|opi|1141910107-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.
<< |< 1 2 >| >> 13 Einträge, 2 Seiten



View all threads created 2006-03-09 11:20.