Seite 1 von 1

Server im Loop

Verfasst: Mittwoch 16. Januar 2008, 12:18
von droptix
Habe mir zum Rumspielen einen simplen SMTP-Server (smtpd Modul) geschrieben. Wenn ich den auf der Konsole starte, kommt das Programm ja in einen Loop und wird quasi nie beendet.

Ich kann den Server eigentlich nur durch Strg+C brutal beenden, wobei der Socket aber in Benutzung bleibt… jedenfalls wird der Server nicht ordnungsgemäß beendet, obwohl es eine close() Methode gibt.

1) Wie kann ich den Socket (unter Debian/Ubuntu) wieder freigeben? Gibt's da einen Konsolenbefehl? Auf die Socket-Option "Re-Use" habe ich keinen Einfluss, da der Socket im asyncore Modul erstellt wird und nicht in meinem Programmcode.

2) Wie kann ich den Server ordnungsgemäß beenden, wenn er sich im Loop befindet?

3) Ich möchte den SMTP-Server als Daemon starten und mir das lästige manuelle Starten nach dem Hochfahren ersparen. Nun habe ich aber das Problem mit dem Loop und brauche außerdem die start, stop und restart Parameter.

Verfasst: Mittwoch 16. Januar 2008, 12:36
von Leonidas
Naja, du musst eben die Klasse überschrieben und deine eigene Busy-Loop machen, dann kannst du sie auch abbrechen.

Re: Server im Loop

Verfasst: Mittwoch 16. Januar 2008, 12:47
von Rebecca
droptix hat geschrieben:1) Wie kann ich den Socket (unter Debian/Ubuntu) wieder freigeben? Gibt's da einen Konsolenbefehl? Auf die Socket-Option "Re-Use" habe ich keinen Einfluss, da der Socket im asyncore Modul erstellt wird und nicht in meinem Programmcode.
der asnyncore.dispatcher und der asynchat.async_chat haben jeweils die Methode set_reuse_addr().

droptix hat geschrieben:2) Wie kann ich den Server ordnungsgemäß beenden, wenn er sich im Loop befindet?
Du kannst den KeyboardInterrupt natuerlich abfangen, um Aufraeumarbeiten zu erledigen. Ausserdem waere das atexit-Modul einen Blick wert.
droptix hat geschrieben:3) Ich möchte den SMTP-Server als Daemon starten und mir das lästige manuelle Starten nach dem Hochfahren ersparen. Nun habe ich aber das Problem mit dem Loop und brauche außerdem die start, stop und restart Parameter.
Normalerweise schreibt man ein (Shell-)Script, welches bei start das Programm startet uns sich die PID in einer Datei mekrt, und welches bei stop und restart die ensprechenden Signale an das Programm schickt. Dein Programm sollte dann natuerlich die entsprechenden Signalhandler implementieren.

Verfasst: Mittwoch 16. Januar 2008, 12:47
von droptix
Hum, interessiert das als Daemon überhaupt, wenn das Skript in der Konsole einen Loop erzeugt, der nie beendet wird?

Ich weiß gar nicht wie das beim Apache ist… unter Windows muss man ja auch immer ein Fenster offen haben, es sei denn Apache läuft als Dienst. Sobald man es schließt, bricht man den Server anscheinend brutal ab.
Rebecca hat geschrieben:der asnyncore.dispatcher und der asynchat.async_chat haben jeweils die Methode set_reuse_addr().
Das wäre einen Versuch wert. Aber gibt es keinen Linux-Befehl, um einen Port wieder freizugeben? So als Notlösung…
Rebecca hat geschrieben:Ausserdem waere das atexit-Modul einen Blick wert.
Ach das geht auch beim brutalen Abbruch mit Ctrl+C?
Rebecca hat geschrieben:Normalerweise schreibt man ein (Shell-)Script, welches bei start das Programm startet uns sich die PID in einer Datei mekrt, und welches bei stop und restart die ensprechenden Signale an das Programm schickt. Dein Programm sollte dann natuerlich die entsprechenden Signalhandler implementieren.
Jo, das hatte ich schonmal erfragt, bin aber daran gescheitert. Habe zwar denke ich das mit den Signal-Handlern in Python verstanden, aber viel weiter hab ich's nicht geschafft.

Gibt's dafür Step-by-Step Tutorials im Netz? Oder kann man sich das bei einem typischen Linux-Dienst abkupfern? Welcher wäre geeignet?

Verfasst: Mittwoch 16. Januar 2008, 13:12
von Leonidas
droptix hat geschrieben:Das wäre einen Versuch wert. Aber gibt es keinen Linux-Befehl, um einen Port wieder freizugeben? So als Notlösung…
Der Kernel gibt Ports selbst wieder frei, nach einigen Minuten.
droptix hat geschrieben:
Rebecca hat geschrieben:Ausserdem waere das atexit-Modul einen Blick wert.
Ach das geht auch beim brutalen Abbruch mit Ctrl+C?
Ja, und Strg+C ist kein brutaler Abbruch sondern schickt einfach nur ein Signal, auf was der Interpreter mit KeyboardInterrupt reagiert. Das nutze ich für meinen Enter-on-Exit-Handler. Also entspricht Strg+C eher dem SIGTERM statt dem SIGKILL.

Verfasst: Mittwoch 16. Januar 2008, 13:43
von Rebecca
Mal ein schneller Entwurf:

myserver.py:

Code: Alles auswählen

#!/usr/bin/env python

import time
import signal
import sys

def on_signal(signum, frame):
    print "Terminating..."
    sys.exit(0)

signal.signal(signal.SIGTERM, on_signal)

#So koennte man auch das ctrl-c abfangen:
#signal.signal(signal.SIGINT, on_signal)

while True:
    print "Running..."
    time.sleep(1)
Das startscript:

Code: Alles auswählen

#!/usr/bin/env python

import sys
import subprocess
import signal
import os

def start():
    f = open("PID_FILE", "w")
    pid = subprocess.Popen(["./myserver.py"]).pid
    f.write("%i\n" % pid)
    f.close()


def stop():
    f = open("PID_FILE")
    pid = int(f.read())
    f.read()
    os.kill(pid, signal.SIGTERM)
 

if sys.argv[1] == "start":
    start()
if sys.argv[1] == "stop":
    stop()
if sys.argv[1] == "restart":
    stop()
    start()