Programm doppelt öffnen verhindern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Montag 26. Juli 2004, 09:48

Hallo,

Ich möchte verhindern das ein Programm dopppelt geöffnet werden kann, wenn es bereits läuft. Ich arbeite auf Windows. Hat jemand eine Idee :?:

Weiter möchte ich , falls das Programm bereits läuft, in dieses eingreifen können. Das heißt eine Funktion in diesem aufrufen.

Könnt ihr mir bitte weiterhelfen.
Gruß, Harry
fs111
User
Beiträge: 170
Registriert: Samstag 15. November 2003, 11:42
Kontaktdaten:

Montag 26. Juli 2004, 09:57

Ich denke in beiden Fällen sind Sockets die richtige Lösung. Binde einfach beim Programmstart Dein Programm an einen TCP-Port. Wenn dann die zweite Instanz startet, kannst Du das abfangen, und mit einer Fehlermeldung beenden. Für zweiteres kannst Du auch Sockets sehr gut benutzen, einfach Kommunikation via TCP.

HTH

fs111
Pydoc-Integration in vim - Feedback willkommen: http://www.vim.org/scripts/script.php?script_id=910
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Montag 26. Juli 2004, 10:24

Hallo fs111,

Danke für deine sehr schnelle Antwort. Ich habe leider überhaupt keine Ahnung von Sockets. Ich weiss nicht mal was damit gemeint ist. Könntest du mir das bitte ein wenig erklären und mir vielleicht ein Beispiel für die Lösung meines Problems zeigen.
Das wäre super. Danke :D
Gruß, Harry
Sorgenkind
User
Beiträge: 34
Registriert: Samstag 24. Juli 2004, 19:25
Kontaktdaten:

Montag 26. Juli 2004, 11:00

unter windows macht man das eigentlich mit DDE ... geht auch recht einfach.
bei win32all ist ein beispiel für DDE server und client dabei....

sockets wären natürlich OS unabhängiger
fs111
User
Beiträge: 170
Registriert: Samstag 15. November 2003, 11:42
Kontaktdaten:

Montag 26. Juli 2004, 11:30

Sockets sind die Endpunkte der Datenübertragung bei Netzwerkkommunikation (Unix-Domain-Sockets lasse ich mal außen vor) via TCP und UDP, also die Technik, die es Dir ermöglichen über Netwerke hinweg zu kommunizieren. Genauso wie Dein Browser und der Server dieses Forums es tun. Die beiden Protokolle, die dafür in zuständig sind, sind TCP (Transmission Control Protocol) und UDP (User Datagram Protocol), welche beide über Sockets kommunizieren (dafür braucht man auch die Port-Nummern). Du solltest hierbei TCP verwenden, da es eine zuverlässige Datenübertragung bereit stellt (reliable). Du würdest für das Locking einfach einen Socket an einer bestimmten Portnummmer öffnen (am besten möglichst hoch), und damit wäre schon alles getan, da immer nur ein Dienst/Programm einen Portnummer zur gleichen Zeit belegen kann, würde die zweite Instanz den Socket nicht öffnen können, und genau dieses könntest Du abfangen. Da Du ja nun schon eine Applikation hast, die auf Anfrage wartet, kannst Du darum noch ein Commando-Interface basteln, welches Kommandos von einem Client, der sich zur Anwendung verbindet entgegen nimmt.

Da ich jetzt nicht weiß, wie bewandert Du mit Netwerken, TCP/IP etc bist, kann ich hier auch noch sehr viel mehr schreiben, oder Du sagst, wo Du dann Probleme hast.

Als Python-Einstieg: http://www.amk.ca/python/howto/sockets/

und falls Du noch Links zu TCP/IP-Themen brauchst, sag einfach Bescheid.

fs111
Pydoc-Integration in vim - Feedback willkommen: http://www.vim.org/scripts/script.php?script_id=910
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Montag 26. Juli 2004, 12:45

Hallo zusammen,

warum mit Kanonen auf Spatzen schießen?

Erstell doch beim Programmstart einfach eine Datei, die beim Programmende wieder gelöscht wird. Unter windows gibts ja sicher auch ein C:\\tmp Verzeichnis oder so wo das einfach möglich ist. Bevor die Datei beim Programmstart erstellt wird einfach testen ob sie schon existiert, dann läuft das Programm schon und es kann eine entsprechende Meldung ausgegeben werden.

Code: Alles auswählen

import os, sys

def main():
    pass # hier ist das Hauptprogramm

tmplockname = "C:\\tmp\testprog.lock"

if os.path.exists(tmplockname):
    print "Testprog läuft schon"
    sys.exit()

f = file(tmplockname,'w')
f.write(" ")
f.close()

main()

os.remove(tmplockname)

Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Montag 26. Juli 2004, 12:49

Hi. So kann aber keine Funktion im anderem Programm gerufen werden... Ich würde das mit den Sockets auch so handhaben, da dann beim gewaltsamen Abschuss des Programmes auch der Port wieder geschlossen wird. Die Datei würde weiter bestehen bleiben...
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Montag 26. Juli 2004, 15:37

Hallo,

Schon mal vielen Dank für alle eure Gedanken.

Ich werde die von fs111 empfohlene Doku zur Socketprogrammierung mal unter die Lupe nehmen. Das ist genau das was ich brauche. Ich werde mich wieder rühren wenn ich Probleme damit habe. :lol:
Gruß, Harry
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Dienstag 27. Juli 2004, 08:27

Hallo,

Ich habe folgendes ausprobiert:

Code: Alles auswählen

try:
    HOST = ''                 # Symbolic name meaning the local host
    PORT = 1234567890         # Arbitrary non-privileged port
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen(1)    
except:
    sys.exit()
Diesen Code habe ich am Anfang meines Programms gehängt. Starte ich es doppelt, bricht er wie erwünscht ab. Gut so.

Nun habe ich gleichen Code in ein Modul geschrieben und dieses Modul dann am Anfang meines Programms gestartet. Dann bricht er nicht wie gewünscht ab. Warum?
Gruß, Harry
fs111
User
Beiträge: 170
Registriert: Samstag 15. November 2003, 11:42
Kontaktdaten:

Dienstag 27. Juli 2004, 09:09

Die Portnummer ist viel zu groß! TCP und UDP-Ports gehen von 1-65536, die von Dir angegebenen Zahl sprengt alle Grenzen, ich wundere mich, dass es überhaupt funktioniert hat...


Hier mal ein paar Hintergründe zu TCP/IP:

http://www.rvs.uni-bielefeld.de/~heiko/ ... nhalt.html
http://de.wikipedia.org/wiki/TCP/IP-Referenzmodell
http://de.wikipedia.org/wiki/TCP
http://www.redbooks.ibm.com/pubs/pdfs/r ... 243376.pdf


fs111
Pydoc-Integration in vim - Feedback willkommen: http://www.vim.org/scripts/script.php?script_id=910
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Dienstag 27. Juli 2004, 09:19

Hallo,

Ich habe es auch mit einem innerhalb des Bereichs liegenden Wert versucht (65007 - so wie in der Python-Doku). Der gewünschte Erfolg bleibt jedoch aus, sobald ich über ein Modul arbeite.
Das Modul sieht so aus:

Code: Alles auswählen

# -*- coding: iso-8859-1 -*-
import socket
import sys

def DoConnect():
    try:
        HOST = ''            # Symbolic name meaning the local host
        PORT = 65007         # Arbitrary non-privileged port
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind((HOST, PORT))
        s.listen(1)
    except:
        sys.exit()
Ich rufe das Modul aus meinem Hauptprogramm auf und starte die Funktion 'DoConnect'.
Gruß, Harry
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Dienstag 27. Juli 2004, 09:55

Hi. Wahrscheinlich wird der Socket sofort wieder gelöscht, da er ja nur in einer Funktion ohne Rückgabe steht. Probier mal das hier:

Code: Alles auswählen

# -*- coding: iso-8859-1 -*- 
import socket 
import sys 
_sock=[None]

def DoConnect():
    try: 
        HOST = ''            # Symbolic name meaning the local host 
        PORT = 65007         # Arbitrary non-privileged port 
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        s.bind((HOST, PORT)) 
        s.listen(1)
        _sock[0]=s
    except: 
        sys.exit()
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Dienstag 27. Juli 2004, 10:18

Hi,

Ja, super, es geht!
Aber ich verstehe noch nicht so genau was da passiert. könntest su mir das bitte erklären :oops:

Jetzt muss ich es nur noch schaffen in dem Hauptprogramm eine Funktion aufzurufen. Könntest du mir dabei bitte auch einen Lösungsansatz schenken?

Jetzt ist mir noch eine Frage eingefallen. Was ist wenn die Portnummer schon von einem anderem unabhängigen Programm belegt ist? Dann startet mein Programm nicht mehr, oder? Wie kann ich das verhindern?
Gruß, Harry
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Dienstag 27. Juli 2004, 11:37

Hi. In einer Funktion sind alle Variablen lokal, d.h. du kannst von außen nicht auf HOST oder PORT in DoConnect zugreifen. Sie existieren also nur während des Funktionsaufrufes und werden danach vom Python Garbage Collector wieder gelöscht (es existiert kein Verweis mehr auf sie, also werden sie nicht mehr gebraucht). Wenn nun aber s gelöscht wird, wird der Socket gleich wieder geschlossen. Das soll verhindert werden. Also hab ich eine Liste außerhalb der Funktion definiert, in die s dann eingetragen wird. So existiert der Socket zwar nicht mehr als s, aber als Teil der Liste _sock und wird nicht gelöscht. Es ist egal, ob du eine Liste oder etwas anderes nimmst, nur bei einer Liste brauch ich kein global einzusetzen, damit ich auch aus der Funktion heraus schreibend zugreifen kann.
HarryH hat geschrieben:Jetzt muss ich es nur noch schaffen in dem Hauptprogramm eine Funktion aufzurufen. Könntest du mir dabei bitte auch einen Lösungsansatz schenken?
Dazu ist es unter anderem ganz nützlich, dass du den Socket noch weiter speicherst. So kannst du Daten darüber empfangen. Hier mal ein längeres Codebeispiel, was dein Modul schon mal in die Richtung ausbaut:

Code: Alles auswählen

# -*- coding: UTF-8 -*-
import socket
import sys
import threading
_sock=[None]
HOST = 'localhost'
PORT = 65007


class Miniserver(threading.Thread):
	def __init__(self,sock):
		threading.Thread.__init__(self)
		self.s=sock
	def run(self):
		while 1: # Empfange Anfragen vom 2. Programm
			conn, addr = self.s.accept()
			print 'Connected by', addr
			while 1:
				data = conn.recv(1024)
				if not data: break
			conn.close()
			Funktion(data)

def Funktion(text):
	print "Habe Nachricht empfangen: %s"%text

def DoConnect():
	try:
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.bind((HOST, PORT))
		s.listen(1)
		_sock[0]=s
		serv=Miniserver(s)
		serv.start()
		print "Server gestartet"
	except: #Hauptprogramm existiert, verbinde mit Programm
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.connect((HOST, PORT))
		s.send('Hello, world')
		s.close()
		print "Funktion gestartet, beende mich..."

if __name__=="__main__":
	DoConnect()
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Dienstag 27. Juli 2004, 14:10

Danke! Funktioniert schon recht gut.

Nur habe ich nun das Problem, das mein Programm nicht beendet werden kann, da er bei 'self.s.accept()' wartet. Also auch wenn ich in meinem Hauptprogramm sys.exit() aufrufe läuft es weiter.

Was hat das schon wieder zu bedeuten?
Gruß, Harry
Antworten