FoxProFoxPro Developer's Conference '94 |
Session 131
Grundlagen der netzwerkfähigen Programmierung
Jürgen Wondzinski
ProLib GmbH
Schon seit ca. 1988 an wurde in der Fachliteratur mit schöner Regelmäßigkeit jedes Jahr als das "Jahr des Netzwerks" bezeichnet. Durch ständig sinkende Hardwarepreise wurden Netzwerke nun auch in den kleinen Büros interessant, so daß nun viele zuerst als Einzelplatzanwendung geschriebene Programme auf den Multiuser-Betrieb umgestellt werden müssen. Diese Änderungen betreffen zum Einen Anpassungen an neue Funktionen, die nur ein Netzwerk bietet (Drucker-Spooling, Transaction Tracking, Email), zum Andern die durch Multiuser-Betrieb entstehenden Problematiken wie Datei- und Satzsperren usw. Aber gehen wir erst mal Schritt für Schritt vor:
Unterschied SingleUser zu MultiUser:
In der normalen Einzelplatzumgebung läßt sich's einfach programmieren: Man ist Herr der Dinge, während man einen Datensatz ändert, kann nichts anderes mit ihm passieren. Ganz anders ist die Situation im Netzwerk: Da mit Ihnen noch andere Stationen gleichzeitig mit den Daten arbeiten, ist es normalerweise die Ausnahme, daß Sie z.B. ohne weitere Vorkehrungen einfach einen PACK durchführen können.
Grundsätzlich gilt außerdem, daß nur die Daten gemeinsam zur Verfügung stehen. Alle Variablen, Arrays und SQL-Cursordateien sind nur auf dieser einen Station sichtbar. Es ist nicht möglich, daß eine andere Station Ihre Cursordatei überschreibt. Wichtig ist ebenfalls, daß jede Station einen eigenen Satzzeiger (Recordpointer) hat, ebenso wie jede Station die Indexsortierung unabhängig voneinander einstellen kann.
Dadurch, daß die Daten zentral an einem Ort (dem Server) gehalten werden und alle Anwender gleichzeitig Zugriff zu den Daten haben und z.B. neue Datensätze anlegen oder sie verändern, müssen Sie spezielle Vorsichtsmaßnahmen walten lassen, damit dies alles ohne Probleme abläuft.
Gottseidank sind die prinzipiellen Änderungen bei FoxPro nicht allzu kompliziert, denn:
Die grundsätzliche Änderung besteht eigentlich nur im Einfügen zweier Befehle in ihrem Startprogramm, noch bevor irgendeine Datei geöffnet wird.
SET EXCLUSIVE OFF
SET REPROCESS TO AUTOMATIC
Damit kommen Sie schon ganz gut über die Runden! Ab sofort wird jede Datei im SHARED Modus geöffnet, und FoxPro kümmert sich um die erforderlichen Sperren.
Klingt zu gut um wahr zu sein, nicht wahr? Nun ja, wenn's soo einfach wäre, müsste ich mir hier nicht die Finger platt tippen.... Also, schaun mer mal.
Datei- und Satzsperren
In FoxPro gibt es verschiedene Abstufungen in der Steuerung des Datenzugriffs:
SHARED:
Alle Daten sind allen im Netz lesend und schreibend zugänglich. Im Normalfall wird man also immer im SHARED Modus die Dateien öffnen.
RECORD LOCK:
Ein oder mehrere Datensätze sind gegen das Schreiben geschützt, können aber weiterhin gelesen werden. Typischer Anwendungsfall: Sobald ein Datensatz bearbeitet wird, wird dieser mit einer Satzsperre belegt, dadurch ist gewährleistet, daß nicht gleichzeitig zwei Stationen den selben Datensatz verändern.
FILE LOCK:
Eine gesamte Datei ist gegen das Schreiben gesperrt, kann aber weiterhin gelesen werden. Bei einigen Aktionen wird es nötig sein, die gesamte Datei mit Schreibschutz zu belegen: z.B. wenn Sie einen Monatsbericht o.ä. drucken; Sie würden in Teufels Küche kommen, wenn die Endsumme eines Berichtes nicht mit den Einzelposten übereinstimmen würde. Auch FoxPro selbst setzt automatisch einen File Lock bei bestimmten Befehlen (Siehe Aufstellung)
EXCLUSIVE:
Die Datei kann nur von einer Station geöffnet werden, alle anderen Stationen haben keinen Zugriff. Diesen Modus benötigen Sie meist bei generellen Wartungsarbeiten (Reorganisation usw.) FoxPro verlangt exklusiven Zugriff bei den Befehlen:
INDEX ON... INSERT
[BLANK]
MODI STRUC PACK
REINDEX ZAP
Falls zum Zeitpunkt des Befehls die Datei nicht exclusiv geöffnet war, müssen Sie sie schliessen und mit dem Exclusive Parameter neu öffnen. Hier noch ein Tip fürs interaktive Arbeiten: Normalerweise hat man auch im interaktiven Betrieb den SHARED Modus aktiviert. Um die aktuelle Datei sofort wieder in den exklusiv-Modus zu schalten, können Sie entweder langwierig den Pfad und Dateinamen eintippen, oder aber kurz und schmerzlos:
USE DBF() EXCL
Diese Tabelle zeigt, welche Sperren FoxPro automatisch bei bestimmten Befehlen setzt:
Befehl | Sperrt: |
APPEND | FILE |
APPEND FROM | FILE |
DELETE [ALL | REST | NEXT x] | FILE |
REPLACE [ALL | REST | NEXT x] | FILE |
UPDATE | FILE |
APPEND BLANK | HEADER |
INSERT INTO | HEADER |
APPEND MEMO | RECORD |
DELETE [NEXT 1] | RECORD |
GATHER | RECORD |
MODI MEMO | RECORD |
READ | RECORD |
RECALL [NEXT 1] | RECORD |
REPLACE [NEXT 1] | RECORD und alle angegebenen Dateien in der FIELD Anweisung |
BROWSE EDIT |
RECORD und alle relationierten Sätze |
DELETE RECORD x | RECORD x |
REPLACE RECORD x | RECORD x |
Bei "Header"-Sperren wird von FoxPro nur der Dateikopf für den Zeitraum des Anfügens einzelner Datensätze gesperrt (Im Header ist z.B. die Anzahl Sätze und das letzte Zugriffsdatum gespeichert). Dies ist Multiuser-freundlicher als eine komplette Dateisperre.
Wenn eine Datei auf einer Station im Exclusive Modus geöffnet ist, und Sie von einer anderen Station versuchen, ebenfalls diese Datei zu öffnen, belohnt sie FoxPro mit der Fehlermeldung #3 "Datei wird bereits benutzt". Falls Sie ein DOS Netzwerk einsetzen (alles, was SHARE benötigt) können Sie auch die Fehlermeldung #1705 "Zugriff auf Datei verweigert" erhalten. Sie sollten also Ihre Datei-Öffnungs Routinen dementsprechend erweitern. Ebenso müssen Sie in Betracht ziehen, daß Sie eine Datei nicht exclusiv öffnen können, weil eben noch ein anderer Anwender die Datei offen hat.
Prinzipiell müssen Sie durch eine geeignete LOOP Konstruktion solange probieren, bis Sie den Zugriff bekommen (oder der Anwender abbricht).
lcOldError =
ON("ERROR")
ON ERROR lnFehler = ERROR()
lnFehler = 0
DO WHILE .T.
USE (lcDatei)
DO CASE
CASE lnFehler = 0
EXIT
CASE INLIST(lnFehler, 3, 1705)
WAIT WINDOW "Datei zur Zeit in Benutzung!"
TIMEOUT 1
CASE ....
&& andere Möglichkeiten
ENDCASE
ENDDO
ON ERROR &lcOldError
Ob Sie die Fehlerbehandlung direkt an Ort und Stelle, wie bei obigen Beispiel, durchführen, oder die Kontrolle einer zentralisierten Fehlerroutine übergeben, bleibt Ihren Vorlieben überlassen. Auf der beiliegenden Diskette finden Sie einen mustergültigen Errorhandler von Pat Adams, jeweils als DOS und als Windows Version, der Ihnen zumindest als Fundquelle jeglicher Fehlerbehandlung dienen kann.
Haben Sie nun die Datei erfolgreich öffnen können, ist der weitere Ablauf zuerst einmal identisch zum normalen SingleUser Betrieb: BROWSE, SEEK, usw. funktionieren wie gehabt. Der große Unterschied kommt nun erst beim Verändern der Daten. Egal was sie mit einem Datensatz auch anstellen: Sie müssen den anderen Anwendern im Netz mitteilen, daß dieser Datensatz nun von Ihnen bearbeitet wird. Dies erfolgt normalerweise durch Setzen der Satzsperre mittels RLOCK().Sobald Sie einen Datensatz erfolgreich gesperrt haben, können andere Anwender nur noch lesend auf ihn zugreifen. Nach Beendigung Ihrer Arbeiten wird der Satz mittels UNLOCK wieder freigegeben und ihre Änderungen den anderen Anwendern zur Verfügung gestellt.
Problematisch:
Ohne Satzsperren: | |||||
User A | Zeit ê | User B | |||
Satz lesen | Satz lesen | ||||
Editieren | |||||
Editieren | |||||
Speichern | |||||
Speichern |
Bei diesem Beispiel lesen beide Anwender den selben Datensatz, und beschließen beide, eine Änderung zu machen. User B kann schneller tippen, ist daher früher fertig und speichert ab. User A überschreibt nun mit seinem Speichern alle Änderungen von User B. Sicherlich nicht Sinn eines Netzwerks...
Und so sollte es richtig ablaufen:
Mit Satzsperren: | ||||
User A | Zeit ê | User B | ||
Satz lesen | Satz lesen | |||
Satz gesperrt ! | ||||
Satz sperren ? | Editieren | |||
Satz sperren ? | ||||
Satz sperren ? | Speichern | |||
Satz gesperrt | Entsperren | |||
Satz lesen | ||||
Editieren | ||||
Speichern | ||||
Entsperren |
Durch die Satzsperre muß User A solange warten, bis User B mit seinen Änderungen fertig ist. Erst nach Freigabe kann User A den Datensatz (mit den Änderungen!) nochmals neu einlesen, selbst sperren und bearbeiten.
Achtung: Puffer-Falle!
Ein nicht unwesentlicher Teil von FoxPro's Geschwindigkeit beruht auf den ausgefeilten Datenpufferungs-Methoden. Beim Öffnen liest FoxPro nämlich einen Teil der Daten schon vorweg in seinen Speicher. Alle weiteren Zugriffe auf diese Datensätze erfolgen dann auf diesen Zwischenspeicher. Bei einem Einzelplatzrechner haben Sie damit auch keinerlei Probleme. Im Netzwerkbetrieb kann allerdings folgendes auftreten:
User A und User B stehen (wieder einmal) auf dem selben Datensatz. User A sperrt den Datensatz. Beide kopieren sich den Datensatz in ein Array (z.B. mit dem SCATTER Befehl). User A editiert, speichert seine Änderungen ab und entlässt den Datensatz aus seiner Sperre. User B macht ein erneutes SCATTER, um die Änderungen von User A zu erhalten, aber.... er bekommt die selben Inhalte wie bei dem Scatter vorher! Soviel Sie auch SCATTERn, sie sehen die geänderten Daten nicht. Ursache ist eben jener Puffer: Alle Lese und Schreibaktionen werden auf den Puffer ausgeführt und nicht gegen die "echten" Daten im Netzwerk. Um diesen Effekt auszubremsen müssen Sie FoxPro dazu bringen, den Puffer neu einzulesen:
Die beste Methode ist zweifellos die dritte Option: Grundregel aller Netzwerkanwendungen: Willst du saubere Daten haben, dann mußt du diese sperren. Unser obiges Beispiel können wir also zum ordnungsgemäßen Laufen bringen, indem wir vor dem zweiten SCATTER ein einfaches RLOCK anbringen.
Nun ist es aber in manchen Anwendungen unerwünscht, den Datensatz nur aus Gründen des Puffer-Auffrischens zu sperren. Dann hilft am besten Methode zwei: Ein seltsam anmutendes GOTO RECNO() erledigt dies elegant. FoxPro tritt sozusagen auf der Stelle, aber der Puffer hat den neuesten Wert.
Die SET REFRESH Option ist, da sie zu einem ständigen Neueinlesen alle <x> Sekunden führt, ein Netzwerk-Performance Killer. Stellen Sie sich 20 oder 50 Stationen vor, die allesamt z.B. jede 5 sec. ihren Puffer erneuern, sprich: die nächsten 10 oder 20 Datensätze frisch einlesen. Daher sollte die SET REFRESH Einstellung nur dann ungleich 0 gesetzt, wenn sie wirklich benötigt wird. (Mehr dazu noch beim Thema BROWSE)
Temporäre Dateien und Indices im Netzwerk
In so ziemlich allen Anwendungen werden temporäre Dateien angelegt und wieder gelöscht. In Einzelplatzanwendungen werden dieDateinamen dafür meist fest vorgegeben (wobei "TEMP" sicherlich der mit Abstand meist verwendete Name sein dürfte J ). Davon müssen Sie sich in Netzwerkumgebungen leider trennen. Über die Funktionen SYS(3) und SYS(2015) können sie sich jederzeit einen eindeutigen Dateinamen zusammenstellen. Die Wahrscheinlichkeit, daß diese Funktionen einen doppelten Dateinamen zurückgeben ist sehr gering. Persönlich habe ich es auf einem sehr schnellen Rechner schon geschafft, bei zwei direkt hintereinander liegenden SYS(3) Aufrufen dieselbe Zeichenkette zurückzubekommen. Dies kommt vermutlich in der Praxis kaum vor, aber hier hilft das einfache Einfügen von einem weiteren Programmschritt zwischen den beiden SYS(3) Aufrufen.
Viel wahrscheinlicher (und trotzdem äussert selten) ist das gleichzeitige Vergeben desselben Dateinamens von unterschiedlichen Netzwerkstationen. Dies ist mir allerdings schon des öfteren gelungen: Bei Schulungen ist dies ein beliebter Vorführeffekt. (Alle Schüler starten gleichzeitig eine Testfunktion). Der von SYS(3) zurückgegebene Wert beruht auf Systedatum und Uhrzeit, und nachdem die Systemuhren der Rechner beim Einloggen in Novell automatisch synchronisiert werden, ist dies also leicht möglich.
Die neuere Funktion SYS(2015) nimmt daher noch Informationen aus dem RechnerBIOS heran, um die Nummern eindeutiger zu machen. Mit dieser Funktion ist mir der obige Effekt noch nie gelungen. Allerdings ist der zurückgegebene String zehnstellig, sodaß sie für einen Dateinamen nur die letzten acht Stellen verwenden sollten.
lcTempName = SUBSTR(SYS(2015),3) + ".DBF"
Des weiteren sollten Sie alle temporären Dateien im EXLUSIV Modus öffnen. Auf diese Weise erhöhen Sie die Geschwindigkeit und die Sicherheit, daß nicht aus Versehen eine temporäre Datei von einer anderen Station mitverwendet wird. Cursordateien sind übrigens prinzipiell exclusiv, da sie ja nur im Speicher Ihrer Arbeitsstation existieren.
Außerdem ist es eine gute Methode, das Temporärverzeichnis auf die lokale Platte zu legen (siehe TMPFILES Eintrag in der CONFIG.FPW), und alle temporären Dateien dort anzulegen. Falls die TMPFILES Einstellung nicht existiert, verwendet FoxPro/WIN das TEMP-Verzeichnis von Windows; FoxPro/DOS das aktuelle Arbeitsverzeichnis.
Den Pfad dieses Verzeichnisses erhalten Sie mit der SYS(2023) Funktion. Dummerweise hat diese Funktion zwei gravierende Mängel: Zum Einen überprüft sie nicht das Vorhandensein dieses Verzeichnisses (Problem entsteht z.B. durch Schreibfehler in der CONFIG.FPW, oder Directory gelöscht/umbenannt); zum Zweiten liefert sie unterschiedliche Ergebnisse unter FoxPro/DOS und /WIN:
? SYS(2023) =>
DOS: "C:"
=> WIN: "C:\TEMP"
Hier nun eine Ersatzfunktion, die Ihnen das tatsächlich von FoxPro verwendete Verzeichnis zurückliefert:
*******************************************
lnOldSelect = SELECT()
RETURN lcPfad
FUNCTION GetTempDir
*******************************************
PRIVATE ALL LIKE l*
CREATE CURSOR (SYS(2015)) (Schrott C(1))
lcPfad = LEFT(DBF(),RAT("\",DBF()))
USE
SELECT (lnOldSelect)
Die Funktion beruht auf der Tatsache, daß Cursordateien immer im Temporärdirectory verankert werden. Als kleine Annehmlichkeit am Rand ist diese Pfadangabe auch immer mit einem Backslash abgeschlossen.
Rechte im Netzwerk
Hier müssen wir unterscheiden zwischen den Rechten für das Applikationsverzeichnis und den Rechten im Datenverzeichnis. In Netzwerken ist es allgemein üblich Programme und Daten in getrennten Verzeichnissen zu halten. Dies zum Einen aus Gründen der einfacheren Datensicherung, zum Anderen aus Gründen des Zugriffsschutzes.
Unter der Voraussetzung, daß die FoxUser.dbf und die temporären Daten in einem lokalen Verzeichnis gehalten werden, benötigt das Applikationsverzeichnis nur SCAN und READ Zugriff. Für das Datenverzeichnis müssen normalerweise alle Rechte vergeben sein (READ/WRITE/SCAN/ERASE).
Beim Abprüfen auf existierende Verzeichnisse ist diese Methode weit verbreitet:
IF FILE("C:\TESTDIR\NUL")
Unter Novell ist diese Methode leider nicht brauchbar, sie meldet immer .T.. Auch sagt das Vorhandensein eines Verzeichnisses noch lange nichts darüber aus, ob sie tatsächlich auch das Verzeichnis beschreiben dürfen. (Möglicherweise haben sie ja nur Leserecht). Aus diesen Anforderungen entstand daher die folgende Routine:
************************************************************
lcDummy =
pcDir+"\"+SUBSTR(SYS(2015),3)+".TMP"
RETURN lnResult > 0
FUNCTION DirExist
************************************************************
PARAMETER pcDir
PRIVATE ALL LIKE l*
lnResult = FCREATE(lcDummy)
= FCLOSE(lnResult)
DELETE FILE (lcDummy)
Verwendung von MEM Dateien
Unter Einzelplatzanwendungen war es eine beliebte Methode, globale Einstellungen in einer MEM Datei abzuspeichern. Im Netzwerk haben diese Dateien leider einen Nachteil: Sie werden exklusiv geöffnet, während sie gelesen oder geschrieben werden. Wenn z.B. zwei Stationen genau zur selben Zeit gestartet werden, kann es vorkommen, daß beide versuchen, dieselbe MEM-Datei zu lesen. Dabei bleibt einer auf der Strecke...
Speichern Sie daher alle Ihre Variablen anstelle von der MEM Datei in ein MEMO Feld ab. Dies ist eine relativ unbekannte Fähigkeit von FoxPro :
SAVE TO MEMO system->Memofeld ALL LIKE xy*
Der Effekt ist derselbe wie bei der MEM Datei, dafür haben Sie aber einen sauber geregelten Multiuser-Zugriff.
Generell ist es für solche Grundeinstellungen aber besser, eine zentrale SYSTEM.DBF zu erstellen, die alle Grundwerte enthält (z.B. MwSt, Firmenaddresse, Lizenznummer, usw.) Legen Sie diese Daten als echte Datenbankfelder ab und lassen sie die Datei ständig offen (bei 225 Arbeitsbereichen auch keine Belastung). Dadurch haben Sie diese Werte ständig über Alias-Referenz in allen Programm-Modulen zur Verfügung und müssen nicht teuren Variablennplatz belegen.
MultiUser BROWSE
Das BROWSE ist eines der mächtigsten Teilmodule innerhalb FoxPro's. Auch im Netzwerk zeigt es überragende Fähigkeiten: Alle erforderlichen Sperren und Aktionen werden vollkommen selbsttätig ausgeführt. Durch das sog. "Dirty Read" Verfahren können Sie durch die Tabellen blättern, ohne sich um Satz- oder Dateisperren zu kümmern. Sobald Sie in einem BROWSE-Feld das Editieren anfangen, wird versucht, diesen Satz zu sperren. Solange dies nicht klappt, erscheint der Warnhinweis "Versuche zu sperren - ESC zum Abbruch" Sobald der Datensatz wieder frei wird, wird ein automatischer Refresh durchgeführt. Falls in dem Browse auch relationierte Felder mit angezeigt werden, so wird der betreffende Satz in der Tochterdatei ebenfalls gesperrt; bei SET SKIP TO (1:n Relation) auch alle zum Hauptsatz gehörenden Tochterdatensätze. Also ein Musterbeispiel an netzwerkfreundlicher Programmierung und ein optimales Werkzeug, um die verschiedenen Sperrfolgen selbst auszutesten...
Trotzdem tritt auch hier im Browse das Problem der Puffer auf: Alle angezeigten Datensätze innerhalb des Fensters werden ja einmal eingelesen und sind dann statisch. Wenn Sie also den Recordpointer nicht verschieben, werden auch die Datensätze nicht neu eingelesen, und sie sehen Änderungen, die im Netz gemacht werden, nicht. Hier allerdings kommt nun der SET REFRESH Befehl ins Spiel: Sein erster Parameter bestimmt, wie oft die angezeigten Daten im BROWSE neu eingelesen werden.
SET REFRESH TO 5, 0
BROWSE
SET REFRESH TO 0, 0
Nun werden alle fünf Sekunden die 10 bis 15 Datensätze im Browsefenster neu eingelesen. Ein Kunde von mir, er ist Besitzer eines Lebensmittelmarktes, sitzt nun am liebsten im Büro vor seinem Browse-Fenster, und sieht zu, wie die Warengruppenumsätze kontinuierlich ansteigen, während draussen die Kassen fleissig das Umsatzfeld im Artikelstammsatz erhöhen....
Leider funktioiert dieses automatische Ändern nicht mit Popups a la:
DEFINE POPUP KundList FROM 1,1 PROMPT FIELD KdName+ " | "+KdNr
Dieses Popup wird nur beim ersten Mal erstellt, es wird nicht durch den SET REFRESH Vorgang erneuert. Falls sich die hiermit angezeigten Daten sehr häufig ändern, müssen Sie entweder das Popup jedesmal frisch einlesen, oder auf die Verwendung von Browse umsteigen.
Direktes oder indirektes Editieren
Soll man nun direkt die Datenbankfelder im READ bearbeiten oder besser doch den Datensatz auf Speichervariablen umkopieren und dann bearbeiten? Die Frage ist so alt wie dBase und kann sehr leicht in einen Glaubenskrieg ausarten. Beide Methoden haben ihre Vor- und Nachteile, und je nach Anwendungsfall kann das Ergebnis anders ausfallen.
Wie immer bei religiösen Angelegenheiten, bringt ein Blick in die Vergangenheit etwas Licht ins Dunkel:
Als dBase II anno 1981 auf den Markt kam, war die Dateistruktur mehr als wacklig. Die Daten konnten sehr leicht beschädigt werden, und vor allem konnte dBase damals nur zwei Arbeitsbereiche verarbeiten. Damals wurde aus dieser Zwangslage heraus eine spezielle Programmiermethode entwickelt: Datei öffnen, Datensatz in Variablen kopieren, Datei schließen. Nur keine Risiken eingehen! Nach dem Editieren wurde die Datei wieder geöffnet, der Datensatz geschrieben, und sofort wieder geschlossen. Mit Erscheinen von dBaseIII+ wurde das Produkt wesentlich stabiler, doch trotz MultiUser-Fähigkeiten mußte man selbst für die Recordlocks sorgen. Die zehn Arbeitsbereiche sorgten zwar dafür, daß man nicht mehr so oft die Dateien schliessen mußte, aber ansonsten gab es noch keinen Grund, von den erprobten Methoden abzuweichen.
Mit Erscheinen von FoxBase/LAN, das wesentlich stabiler und schneller als dBaseIII+ war, hielten erste automatische RecordLocks Einzug. Da aber die Implemetierung nicht vollständig war, blieben die meisten Programnmierer beim Variablen-Editieren. Aber seit dem Erscheinen von FoxPro 1.0 hat sich das Blatt gewandelt. Erstmals war es nur noch in Sonderfällen notwendig, explizite Sperren zu setzen, erstmals erledigte die Engine das meiste. Aus diesen Gründen heraus begannen viele Programmierer den Umstig zur direkten Editierung:
Gegen das direkte Editieren werden gerne zwei Gründe angeführt:
Zu Punkt eins ist zu sagen, daß meine Beobachtungen darauf hindeuten, daß Änderungen in der Regel gewollt sind, und nur in Ausnahmefällen abgebrochen wird. Auch ist die Netzwerk und PC-Hardware in der heutigen Zeit so zuverlässig geworden, daß Rechnerabstürze eher selten geworden sind. (Nun gut, bei uns als Entwicklern ist das anders... J ) Falls also beim direkten Editieren ein Vorgang abgebrochen werden muß, so genügt das Sicherstellen des Datensatzes in einem Array vor Beginn des Editierens. Nur bei einem Abbruch muß dann dieses Array zurückgesichert werden. Der generelle Ablauf sieht also etwa so aus:
USE Datei
SEEK Datensatz
SCATTER TO Array && nur notwendig für Abbruch
READ
IF LASTKEY() = ESC && entfällt wenn ohne Abbruch
GATHER
ENDIF
Beim indirekten Editieren sind so ziemlich die selben Schritte notwendig:
USE Datei
SEEK Datensatz
IF RLOCK()
SCATTER MEMVAR
READ
IF LASTKEY # ESC
GATHER
ENDIF
ENDIF
Daraus folgt, daß vom grundlegenden Schema her das direkte Editieren den Sieg davontragen kann. Ähnlich sieht es aus, wenn man die Programmierung betrachtet.
Dafür ist beim direkten Editieren der zentrale Dreh- und Angelpunkt ein sauber funktionierendes Fehlermanagement. Hier sei nochmals auf die ProError und ProErrorW Datei hingewiesen. In Verbindung mit diesem ausgefeilten Errorhandler können 99% aller Multiuserprobleme getrost vergessen.
Der andere Punkt (Datensatz ist dauerhaft gesperrt) spielt bei FoxPro eine eher untergeordnete Rolle, denn selbst wenn der Satz durch das READ gesperrt ist, kann er ja immer noch gelesen werden! Und auch beim Variablen-Editieren ist eine Grundvoraussetzung das saubere Sperren während die Variablen editiert werden.
Die Alternative zu diesem pessimistischen Locking ist das optimistische Locking, nach dem Motto: Ich brauch den Datensatz im Normalfall nicht sperren".
In einem zusätzlichen Feld in der Datei wird bei jedem Update ein Zähler oder ähnliches hochgezählt. Ab und an trifft man auch Versionen, die Datum, Uhrzeit und User hier abspeichern). Beim Einlesen des Datensatzes merkt man sich diesen Wert, beim Abspeichern der geänderten Daten muß nun zuerst überprüft werden, ob der Stand im Zählerfeld noch identisch ist. Wenn ja, ist alles gut gegangen, mein Optimismus wurde belohnt, und ich kann die Daten abspeichern. Wenn nein, dann ist der Anwender arm dran, denn nun wird der inzwischen geänderte Datensatz neu eingelesen und unser Anwender darf seine Änderungen nochmals neu erfassen. Durch etwas Mehraufwand kann man nun noch erreichen, daß man Feld für Feld abprüft welches sich überhaupt geändert hat, und nur diese Felder nachbearbeiten läßt.
Unter gewissen Sonderfällen wird eine Spezialform des optimistischen Sperrens durchgeführt: Wenn in einem System zwei verschiedene Datenbereiche einer Datei von zwei verschiedenen Abteilungen gepflegt werden, kann es Sinn machen, auf Variablen zu editieren und den Datensatz nicht dauerhaft zu sperren. Dadurch, daß jeder Prozess nur einen Teil der Felder bearbeitet, und keine Übserschneidungen vorkommen, können beide Update-Prozesse parallel laufen.
Alles in Allem ein wesentlicher Mehraufwand, dessen Nutzen meist in keinem Verhältnis zum Aufwand steht. Desweiteren können bei Verwendung solcher Sperrmechanismen keine Fremdprogramme mehr mit den selben Daten arbeiten, da sie von diesen Regeln keine Ahnung haben.
Hardware Grundlagen
Egal, welches Netzwerk Ihr Kunde einsetzt: um Ihre Programme sauber auszutesten, müssen Sie sich selbst auch entsprechend ausrüsten. Nur so können Sie sich hundertprozentig von der Betriebssicherheit Ihrer Programme überzeugen, und dabei gleich auch noch Netzwerkwissen sammeln.
Im einfachsten Fall tut´s ein normaler Multitasking Zusatz wie z.B. DESQview (Quarterdeck) oder unser allseits beliebtes WINDOWS. Dazu muß auch zwingend SHARE geladen sein, damit DOS den Mehrfach-Dateizugriff auch verwalten kann. Beim SHARE Aufruf unbedingt die Zusatzparameter mit angeben: z.B.
SHARE /F:5120 /L:500
ansonsten erhalten Sie über kurz oder lang die kryptische Fehlermeldung "Systemresourcen erschöpft".
Besser ist's schon mit Windows For Workgroups (im folgenden kurz als WinWG bezeichnet): Hier kommt zum Einen ein virtueller Share Treiber (VSHARE.386) zum Einsatz (d.h. unter WinWG muß kein SHARE mehr in der Autoexec geladen werden!). Zum Andern kann man zusammen mit seinem Laptop oder einer anderen Station schon ein kleines Netzwerk aufbauen.
Noch besser ist natürlich die Anschaffung einer 5User Version von Novell, zusammen mit WinWG. Damit haben Sie dann so ziemlich alle Möglichkeiten, die Ihnen im normalen Business vorkommen werden, abgedeckt. Zum Einen können Sie die Novelltypischen Sachen wie Druckspooling, Transaction Tracking usw. verwenden und austesten, zum anderen haben Sie via WinWG auch die "normalen" DOS basierenden Netzwerke im Zugriff. Dem Thema Novellkonfiguration habe ich nachfolgend noch ein Extrakapitel gewidmet.
Später läßt sich diese Konstellation dann noch um einen WinNT Server, erweitern, so daß Sie dann auch noch den MS SQLServer in ihr Netz einbinden können und auf Client/Server Basis programmieren können. Sie sehen, in den nächsten Monaten werden Sie keinerlei Probleme haben, ihr Geld sofort wieder zu investieren....
So, ihr Netzwerk ist aufgebaut. Jetzt geht's ans Einrichten. Wenn möglich sollte ihre Installation so aussehen:
Lokale Platte:
DOS, Windows, FoxPro, Temporäre Dateien
Netzwerk:
Alle gemeinsam genutzten Daten und Hilfsprogramme
In einem großen Netzwerk kann das lokale Installieren von Windows und sonstigen Programmen zu einem Support-Alptraum ausarten, darum wird man dort auf eine Netzwerk-Installation umsteigen. Dies bedeutet, daß alle Programme zentral im Netzwerk liegen, und lokal nur noch die benutzerspezifischen Abweichungen gespeichert werden (INI-Dateien usw.). Dies geht zwar auf Kosten der Performance (alle Programmdateien müssen über das Netzwerk geladen werden) dafür muß z.B. bei einem Update nicht durch das gesamte Haus geturnt werden.
Bitte beachten Sie, daß trotz der Verwendung von nur einer Programmkopie auf dem Server weiterhin Lizenzen für alle angeschlossenen Arbeitsplätze vorhanden sein müssen.
Doch nun zurück zu FoxPro:
Die relativ große Supportbibliotek (FOXPRO.ESL) sollte wenn möglich, auf der lokalen Platte abgelegt werden. Dadurch erfolgt der Start Ihrer Applikation wesentlich schneller. Des weiteren sollten auch alle temporären Dateien lokal gehalten werden. (TMPFILES Eintrag in der CONFIG.FP)
Wenn in einem Netzwerk unterschiedliche Rechnerkonfigurationen existieren, so muß dafür gesorgt werden, daß für jeden Arbeitsplatz eine eigene CONFIG.FP zuständig ist. Über die DOS Variable FOXPROCFG (oder FOXPROWCFG bei FP/WIN) kann zentral der Zugriff auf diese Datei geregelt werden, z.B. indem ein Directory User- bzw. Stationsbezogen gemappt wird. So ist z.B. in meinen Netzwerken das Laufwerk H: immer das Heimatverzeichnis des angemeldeten Users. Darin existiert wiederum ein FoxPro Unterverzeichnis mit seiner CONFIG.FPW, seiner FOXUSER.* usw.
SYS:\
\ALLESAMT => G:
\USER\
\WOODY\ => H: für User Woody
\TOOLS
\FOXPRO
\WASTL\ => H: für User Wastl
\TOOLS
\FOXPRO
\PROGS\ => I:
\WINWORD
\EXCEL
Im Normalfall wird man jedem Anwender seine eigene FOXUSER Datei gönnen, alternativ kann man aber auch allen Anwendern gemeinsam eine zentrale FOXUSER zur Verfügung stellen. Diese muß aber dann auf READ-ONLY gesetzt werden. Falls dies nicht geschieht, greift das erste im Netz gestartete FoxPro im Exklusivmodus auf diese Datei zu, während die nachfolgenden daher keinen Zugriff mehr erhalten.
Sie können die Geschwindigkeit im Netz noch weiter optimieren, indem Sie generell die Verwendung von Resourcedateien unterbinden (SET RESOURCE OFF). FoxPro kann sich dann allerdings keine Fensterpositionen, Rechner- und Kalendereinträge mehr merken, und in FP/DOS gehen ihnen dazu noch die Farb- und Druckereinstellungen verloren. Eine zweischneidige Sache also.
Prinzipiell können wir im FoxPro Bereich zwei Arten von Netzwerken unterscheiden:
Von der Verwendung dieser Netzwerke für echte Datenbankanwendungen wird abgeraten. Die Geschwindigkeit und Datensicherheit ist nicht akzeptabel, da auf der Station mit den Daten immer auch normal gearbeitet werden kann (NONdedizierter Server), besteht die Gefahr, daß diese Station durch Bedienerfehler abgeschossen wird. Daraus resultierend treten meist Platten- (lost Clusters) und Datenfehler ("Keine Tabelle", "Memodatei defekt") auf. Da solche Fehler im Zweifelsfall immer dem Programm bzw. Ihnen als Programmierer angelastet werden, sollten Sie von Anfang an den Kunden zumindest auf die Probleme solcher Konfigurationen hinweisen. Des weiteren haben meist Sie die Folgen auszubaden, sprich: die Daten zu restaurieren.
Setzen Sie alle EXE und Overlaydateien auf Read-Only, ansonsten könnten Sie durch unerklärliche Fehlermeldungen wie "Zugriff verweigert" beim Programmstart beglückt werden.
Da das meistverwendete Netzwerk immer noch das NOVELL Netzwerk ist, hierzu noch einige Tips:
Falls Windows eingesetzt wird, sollte die Workgroups Version installiert werden. Die Peer-to-Peer Eigenschaften ergänzen hervorragend die Novell-Eigenschaften.
Falls Sie noch immer mit den IPX-Treibern arbeiten: IPX ist tot, Novell empfiehlt seit Jahren nur noch die ODI Treiber. Doch inzwischen sind auch diese nicht mehr das Allerneueste: seit der 3.12 und 4.0 Version existiert das Konzept der VLM Module. Aus meiner Erfahrung heraus rate ich zur Zeit trotzdem noch zu den ODI Treibern, da damit alle Programme und Zusatzroutinen einwandfrei funktionieren. Die ODI Treiber haben gegenüber den IPX Treiber den Vorteil, daß sie modular aufgebaut sind. Dies hat u.a. den Vorteil, daß sie durch die geringeren Einzelgrößen leichter in den UMB-Bereich hochgeladen werden können. Bei Netzwerkkartentausch oder Umkonfiguration können die Änderungen durch einfaches Eintragen in der Datei NET.CFG durchgeführt werden, wohingegen der IPX.COM immer neu zusammenkompiliert werden mußte.
Die normale Workstation Konfiguration sieht demnach etwa so aus:
Config.sys
Files = 100
Autoexec.Bat
@echo off
cd\netz
lsl.com
ne2000.com && Netzkartenabhängig
ipxodi.com
netx.exe && Event. auch EMSNETX.EXE
cd\
cls
if not exist g:*.* goto KeinNetz
g:
login
goto Ende
:KeinNetz
echo lokaler Betrieb...
win
:Ende
Sie sollten (wie immer) dafür Sorge tragen, daß nur die neuesten Treiber zum Einsatz kommen. Diese finden Sie am sichersten in CompuServe. Im Forum NOVFILES sind diese jederzeit zum Download bereit.
Falls sie eine ältere Installation auf Vordermann bringen, achten Sie darauf, daß der NETX früher eine COM Datei war, nun ist's eine EXE. Solange Sie aber die COM Datei nicht löschen, wird diese von DOS immer vor der EXE geladen! (Dies ist ein beliebter Trick, um sich stundenlanges Haareraufen zu bescheren...)
EMSNETX sollte immer dann zum Einsatz kommen, wenn Sie sowieso einen EMS Speichermanager verwenden, denn dann können Sie einiges an UMB-Bereich freihalten.
Alle Netzwerktreiber lassen sich übrigens ohne Probleme hochladen.
In dem Unterverzeichnis c:\netz aus obigem Beispiel muß sich noch die Datei NET.CFG befinden. Aus früheren Versionen ist Ihnen vielleicht noch die SHELL.CFG ein Begriff, diese sollten Sie aber sofort zu NET.CFG umbenennen. Diese Textdatei entspricht für Novell in etwa der Config.sys für DOS.
;*** NET.CFG für
Station 02 ****
LINK DRIVER NE2000
FILE HANDLES = 100
SHOW DOTS = ON
SPECIAL UPPERCASE = ON
LOCAL PRINTERS = 1
CACHE BUFFERS = 10
INT 5
PORT 320
PROTOCOLL ETHERNET_802.3
Standardmäßig können Sie nur 40 Dateien auf dem Netzwerk öffnen, erst durch die FILE HANDLES Anweisung wird dies erhöht. Die Summe der FILE HANDLES (Net.cfg) und der FILES (Config.sys) darf zusammen den Wert 254 nicht überschreiten!
Das Novell Dateisystem benötigt die DOS Verzeichniseinträge "." und ".." nicht, für die DOS Kompatibilität sollten Sie daher mit SHOW DOTS die Emulation durch Novell einschalten.
Da Novell standardmäßig die Umlaute in Datei- und Verzeichnisnamen nicht auf Großschrift wandelt, müssen Sie dies in europäischen Ländern gesondert einschalten mittels SPECIAL UPPERCASE.
Falls Sie an der Workstation keinen Drucker angeschlossen haben, können Sie den Wert bei LOCAL PRINTERS auf 0 setzen.
Die CACHE BUFFERS beschleunigen den Netzzugriff, kosten allerdings auch RAM.
Mit den LINK DRIVER Einträgen wird schließlich der eigentliche Netzwerkadapter konfiguriert; sie können bedenkenlos alle Konfigurationen aller verwendeten Netzwerkkarten hier aufführen, der Treiber sucht sich seinen zugehörigen Eintrag selbsttätig. (Wichtig ist die Einrückung der zugehörigen Werte!)
Im Novell Loginscript sollten Sie zum einen automatisch alle benötigten Standardverzeichnisse setzen, z.B. ein Heimatverzeichnis für jeden User getrennt und ein gemeinsames Datenaustausch-Verzeichnis. Zum anderen ist die MACHINE Anweisung hier zu setzen.
MAP ROOT G: =
SYS:/Gemeinsam
MAP ROOT H: = SYS:/USERS/%LOGIN_NAME
MACHINE = "%LOGIN_NAME # %P_STATION "
DOS SET FoxProCfg = "H:\\FOXPRO\\CONFIG.FP"
DOS SET FoxProWCfg = "H:\\FOXPRO\\CONFIG:FPW"
Falls Sie ThirdParty Tools verwenden, müssen Sie noch unbedingt diese Zeile in Novell's STARTUP.NCF eintragen:
SET ALLOW UNENCRYPTED PASSWORDS = ON
Da Novell seit einiger Zeit die Paßwörter im Netzwerk verschlüsselt überträgt, der Algorithmus hierzu aber nicht frei zugänglich ist, müssen Sie Novell mitteilen, daß auch unverschlüsselte Paßwörter erlaubt sind.
Transaction Tracking (TTS)
Das TTS ist ab der Novell Version 2.2 und 3.11 aufwärts standardmäßig im System aktiviert. Aus Performancegründen sollte bei TTS Verwendung das SYS Volume auf einer anderen Platte als das Datenvolume sein. Außerdem muß auf dem SYS Volume auch immer genügend Platz zum Schreiben der TTS Datei sein.
Die zu überwachenden Datei werden mittels FLAG mit dem Attribut "T" markiert. Achtung: Als Transactional gekennzeichnete Dateien können nicht mehr gelöscht oder umbenannt werden. (Wichtig z.B. bei PACK!) Prinzipiell müssen alle zu einer dbf gehörenden Nebendateien als "T" gekennzeichnet werden, also nicht nur die DBF, sondern auch die FPT, CDX und eventuelle IDX Dateien.
Um von FoxPro aus auf das Novell TTS zugreifen zu können, benötigen Sie auf jeden Fall eine Library. Bei FoxPro/DOS ist sie von Haus aus dabei als NETWARE.PLB, bei FoxPro/WIN müssen Sie auf eine käufliche Library zurückgreifen. (Eine Aufstellung finden Sie am Ende des Artikels).
Novell unterstützt prinzipiell zwei Arten von TTS: Implizites und explizites TTS.
Implizit:
Sobald auf einer transactional geflaggten Datei ein logisches oder physisches Locking durchgeführt wird, betrachtet dies Novell als Start einer Transaction. Wenn die Sperre wieder beseitigt wird, ist das gleichbedeutend mit Commit. Nur falls die Station während des Locks abstürzen sollte, wird ein Rollback durchgeführt. D.h. Implizites Locking hilft zwar bei wackeliger Hardware, ist aber bei solchen Ursachen eigentlich die falsche Medizin.
Im Normalfall sollte man daher das implizite Locking abschalten mittels des DOS Utility
SETTTS 255,255
und wenn überhaupt, nur explizites Locking fahren.
Explizit:
Bei diesem Verfahren legen Sie selbst fest, ab wann eine Transaction beginnt, wann sie zu Ende ist, und unter welchen Umständen ein Rollback durchgeführt werden muß. Dazu müssen Sie die jeweiligen Funktionen aus der Library verwenden.
TTSAVAIL()
Stellt fest, ob diese Novell-Version das TTS System
eingeschaltet hat
TTSATTIB()
Setzt bzw liest das TTS Flag einer Datei
BEGINTRAN()
Startet die Transaktion. Alle Veränderungen an der
Datei werden nun protokolliert.
COMMIT()
Die Aktion ist ordnungsgemäß beendet, die Änderungen
dürfen weggeschrieben werden.
RLLBACK()
Im Fehlerfall werden alle aufgezeichneten Änderungen
wieder zurückgenommen.
Durch das Datenbuffersystem von FoxPro kann es allerdings passieren, daß bei einer Transaktion auch Datensätze gesperrt werden, die physikalisch in der Nähe (genauer: innerhalb der Blockgrenze) liegen. Dies ist um so störender, weil eine TTS Sperre den physikalischen Zugriff auf die Datei unterbindet. D.h. Falls Sie mittels BROWSE durch die Datei blättern und dabei in den Bereich einer Transaktion kommen, verfällt FoxPro in einen Wartezustand, der nicht durch Drücken von ESC oder ähnlichem abgebrochen werden kann. Erst die Beendigung der Transaktion entläßt Sie wieder aus der Starre.
Trotzdem kann man das TTS System erfolgreich einsetzen, solange man die zwei Punkte beachtet
die Zeitdauer einer Transaktion so kurz wie möglich halten,
das implizite TTS abschalten.
Unter FoxPro/DOS können Sie direkt die Novell Druckerqueues ansprechen, ohne daß diese erst über den Capture Befehl an einen LPT-Port angebunden sein müssen. So können Sie auf alle im Netzwerk vorhanden Drucker zugreifen:
SET PRINTER TO LPT1
&& Lokaler Drucker
SET PRINTER TO \\SPOOLER\Q=Laser_oben\NB\C=2
Wichtig ist, daß die gesamte Anweisung OHNE Leerstellen angegeben wird. Bei manchen älteren NETX Shells funktionierte übrigens der \NB (No Banner) Schalter nicht. Da sie ja sowieso immer die neuesten Treiber verwenden, trifft sie das aber eh nicht....
Unter Windows können Sie die Druckqueues nicht mehr so einfach umstellen, hier geht alles über Einträge in der WIN.INI. Durch geeignete Routinen können Sie die installierten Drucker genauso abfragen wie die Anschlüsse, mit denen diese verbunden sind.
Um z.B. festzustellen, welche Druckerqueue zur Zeit an LPT1: angeschlossen ist, können Sie diesen Code verwenden:
************************************************************
FUNCTION GetPrCon && = Get Printer Connection
************************************************************
PARAMETER pcPort
SET LIBRARY TO SYS(2004)+"FoxTools.fll" ADDI
lnNetGet =
REGFN("WNetGetConnection", "C@C@I",
"I")
IF lnReturn = 0 AND lnLenStr > 0
RETURN
lcPrintQ = SPACE(70)
lnLenStr = LEN(lcPrintQ)
lnReturn = CALLFN(lnNetGet, pcPort, @lcPrintQ, @lnLenStr)
WAIT WINDOW pcPort + " ist verbunden mit :" +
lcPrintQ
ELSE
WAIT WINDOW pcPort + " ist lokal"
ENDIF
Um einen Drucker umzuleiten, ist folgende Routine brauchbar:
************************************************************
lnNetGet = REGFN("WNetGetConnection",
"C@C@I", "I")
* Zuerst checken, ob überhaupt schon umgeleitet
* Falls umgeleitet, muß zuerst gecancelt werden
* Und nun umleiten
* und gleich mal testen, ob's funktioniert hat:
FUNCTION SetPrCon && = Set Printer Connection
************************************************************
PARAMETER pcPort, pcZiel, pcPasswort
SET LIBRARY TO SYS(2004)+"FoxTools.fll" ADDI
lnNetAdd = REGFN("WNetAddConnection",
"CCC", "I")
lnNetCan = REGFN("WNetCancelConnection",
"CI", "I")
lcPrintQ = SPACE(70)
lnLenStr = LEN(lcPrintQ)
lnReturn = CALLFN(lnNetGet, pcPort, @lcPrintQ, @lnLenStr)
IF lnLenStr > 0
lnReturn = CALLFN(lnNetCan, pcPort, 1)
ENDIF
lnReturn = CALLFN(lnNetAdd, pcZiel, pcPasswort, pcPort)
= GetPrCon(pcPort)
Und so nebenbei haben Sie gleich noch ein bißchen über die FOXTOOLS Library gelernt...
Die nachfolgende Auflistung erklärt die im Netzwerk verwendeten FoxPro Befehle.
Mit SET EXCLUSIVE wird festgelegt, ob Tabellen in einem Netzwerk für alleinigen oder gemeinsamen Zugriff von Benutzern zur Verfügung stehen.
Die Änderung der Einstellung von EXCLUSIVE ändert den Status von vorher geöffneten Tabellen nicht. Wenn z.B. eine Tabelle mit SET EXCLUSIVE ON geöffnet wurde und später SET EXCLUSIVE auf OFF gesetzt wird, bleibt die Tabelle weiterhin nur für alleinigen Zugriff geöffnet.
Der Standard für SET EXCLUSIVE ist ON.
ON
Eine in einem Netzwerk geöffnete Tabelle kann bei SET EXCLUSIVE ON auch nur von dem Benutzer verwendet werden, der die Tabelle geöffnet hat. Andere Netzwerkbenutzer können auf diese Tabelle nicht zugreifen. Im Gegensatz zu FLOCK() verhindert SET EXCLUSIVE ON auch den Nur-Lese-Zugriff für alle anderen Benutzer. Eine Datei im Netzwerk kann auch durch Ausgabe von USE EXCLUSIVE für alleinigen Zugriff geöffnet werden. Satz- und Dateisperren sind bei einer exklusiv geöffneten Tabelle nicht erforderlich.
Durch Öffnen einer Datei für alleinigen Zugriff wird sichergestellt, daß die Datei nicht von anderen Benutzern geändert werden kann. Bei einigen Befehlen ist es erforderlich, daß eine Datei für exklusiven Zugriff geöffnet wird, bevor diese ausgeführt werden können. Hierbei handelt es sich um die Befehle INSERT, INSERT BLANK, MODIFY STRUCTURE, PACK, REINDEX und ZAP.
OFF
Wenn eine Tabelle im Netzwerk mit SET EXCLUSIVE OFF geöffnet wird, können alle Netzwerkbenutzer auf diese zugreifen und sie ändern.
Anzeige von Änderungen bei Sätzen, die von anderen Benutzern im Netz vorgenommen wurden.
Tabellen können im Netz zur gemeinsamen Benutzung geöffnet werden. So können Sätze, die Sie sich gerade ansehen, gleichzeitig von einem anderen Benutzer im Netz bearbeitet werden. Benutzen Sie SET REFRESH, um festzulegen, ob geöffnete Datenblattfenster mit von anderen Benutzern vorgenommenen Änderungen aktualisiert werden sollen oder nicht.
SET REFRESH beeinflußt die Anzeige von Sätzen in einem Datenblattfenster, das mit BROWSE, CHANGE oder EDIT geöffnet wurde. Memofelder, die zur Bearbeitung in einem Datenblattfenster geöffnet sind, werden ebenfalls aktualisiert.
Mit SET REFRESH kann auch angegeben werden, wie oft lokal zwischengespeicherte Daten aktualisiert werden.
Der Standardwert ist 0, 5
<AusdrN1>
Der numerische Ausdruck <AusdrN1> gibt an, wie oft ein Datenblatt- oder Memoeditierfenster aktualisiert wird. <AusdrN1> ist die Anzahl der Sekunden zwischen Aktualisierungen und kann ein Wert zwischen 0 und 3600 sein. Der Standardwert ist 0 Sekunden. Wenn <AusdrN1> ein Wert ungleich 0 ist und andere Benutzer die Sätze, die Sie sich ansehen, ändern, werden die Sätze nach Ablauf des Aktualisierungsintervalls aktualisiert. Ist <AusdrN1> 0, werden die von Ihnen angesehenen Sätze nicht aktualisiert.
FoxPro versucht, einen Satz zu sperren, wenn Sie diesen im Datenblattfenster ändern wollen. Wenn Sie versuchen, einen Satz zu sperren, der bereits von einem anderen Benutzer im Netz gesperrt wurde, erhalten Sie den aktualisierten Satz, wenn der andere Benutzer die Satzsperre aufhebt. Dies ist unabhängig von der Einstellung von SET REFRESH. Die Meldung "Satz wurde geändert." kann ebenfalls angezeigt werden.
<AusdrN2>
Die Netzwerkversionen von FoxPro speichern Teile der Tabellen im Arbeitsspeicher auf Ihrem Arbeitsplatzrechner. <AusdrN2> gibt an, wie oft diese lokalen Datenpuffer mit den aktuellen Daten vom Netzwerk aktualisiert werden. <AusdrN2> ist die Anzahl der Sekunden zwischen den Datenpufferaktualisierungen. Der Standardwert von <AusdrN2> ist 5. Sie können einen Wert zwischen 0 und 3600 angeben. Die Puffer werden nie automatisch aktualisiert, wenn <AusdrN2> 0 ist. Durch RLOCK() und Recordbewegungen (GO / SKIP) werden die aktuellen Werte vom Netz gelesen.
Wenn Sie für <AusdrN1> einen anderen Wert als 0 angeben, <AusdrN2> aber nicht angeben, wird <AusdrN2> auf denselben Wert gesetzt wie <AusdrN1>. <AusdrN2> wird jedoch auf 5 gesetzt, wenn Sie für <AusdrN1> 0 angeben und <AusdrN2> auslassen.
Die Leistung kann verbessert werden, wenn der Wert von <AusdrN2> erhöht wird.
Bestimmen, wie oft oder wie lange FoxPro nach einem erfolglosen Sperrversuch erneut versucht, eine Datei oder einen Satz zu sperren.
Eine Satz- oder Dateisperre ist nicht immer beim ersten Versuch erfolgreich. Häufig wurde ein Satz oder eine Datei von einem anderen Benutzer im Netzwerk gesperrt. Ist eine erste Satz- oder Dateisperre nicht erfolgreich, bestimmt SET REPROCESS, ob zusätzliche Sperrversuche an der Datei/am Satz ausgeführt werden.
Mit SET REPROCESS können Sie die Anzahl der zusätzlichen Sperrversuche oder die Dauer dieser Versuche angeben. Die Angabe einer ON ERROR-Routine beeinflußt die Reaktion auf einen erfolglosen Sperrversuch.
TO <AusdrN> [SECONDS]
Der numerische Ausdruck <AusdrN> gibt an, wie oft FoxPro nach einem erfolglosen Versuch einen erneuten Satzsperrversuch ausführt.
Der Standardwert ist 0.
0
Wenn <AusdrN> 0 (der Standardwert) ist und ein Befehl oder eine Funktion zum Sperren eines Satzes/einer Datei abgesetzt wird, versucht FoxPro, den Satz/die Datei auf unbestimmte Zeit zu sperren. Die Systemmeldung "Versuche zu sperren... mit ESC abbrechen" wird angezeigt, während FoxPro einen Satz- oder Dateisperrversuch ausführt. Wird der Satz bzw. die Datei zur Sperrung freigegeben, während Sie warten, erfolgt die Sperrung, und die Systemmeldung wird gelöscht. Führt eine Funktion die Sperre aus, wird wahr (.T.) zurückgegeben.
Bei Betätigung von ESC als Antwort auf die Systemmeldung wird eine entsprechende Warnmeldung angezeigt (z.B. "Satz wird bereits von einem anderen Benutzer benutzt"). Führt eine Funktion die Sperre aus, wird keine Warnmeldung angezeigt und falsch (.F.) zurückgegeben.
Wenn eine ON ERROR-Routine angegeben wird und ein Befehl versucht, den Satz bzw. die Datei zu sperren, hat die ON ERROR-Routine Vorrang vor zusätzlichen Sperrversuchen. Die ON ERROR-Routine wird sofort ausgeführt. Es werden keine zusätzlichen Sperrversuche ausgeführt, und die Systemmeldung wird nicht angezeigt.
Wenn der Sperrversuch mit einer Funktion erfolgt, wird die Systemmeldung nicht angezeigt, eine ON ERROR-Routine wird nicht ausgeführt, und falsch (.F.) wird sofort zurückgegeben.
-1
Wenn <AusdrN> -1 ist, setzt FoxPro die Satz/Dateisperrversuche auf unbestimmte Zeit fort. Sie können die Sperrversuche nicht mit ESC abbrechen, und es wird keine ON ERROR-Routine ausgeführt. Eine Systemmeldung ("Warte auf Sperre...") wird nur angezeigt, wenn SET STATUS ON ist. Wurde der Satz/die Datei, die Sie sperren möchten, von einem anderen Benutzer gesperrt, müssen Sie solange warten, bis dieser Benutzer die Sperre aufhebt.
<AusdrN> > 0 [SECONDS]
Ist der SET REPROCESS-Wert <AusdrN> größer als 0, können Sie bestimmen, wie oft und wie lange FoxPro Sperrversuche bei einem Satz bzw. einer Datei ausführt. Um die Anzahl der Sperrversuche anzugeben, lassen Sie das Schlüsselwort SECONDS aus. Um die Dauer der Sperrversuche festzulegen, begeben Sie SECONDS an.
Wenn <AusdrN> 30 ist, versucht FoxPro einen Satz oder eine Datei bis zu 30 mal zu sperren. Wird auch das optionale Schlüsselwort SECONDS (SET REPROCESS TO 30 SECONDS) angegeben, wird der Satz- bzw. Dateisperrversuch bis zu 30 Sekunden lang ausgeführt.
Eine Systemmeldung ("Warte auf Sperre...") wird nur angezeigt, wenn SET STATUS ON ist.
Ist eine ON ERROR-Routine angegeben und sind die Sperrversuche erfolglos, wird die ON ERROR-Routine ausgeführt. Führt jedoch eine Funktion den Sperrversuch aus, wird eine ON ERROR-Routine nicht ausgeführt, und die Funktion gibt falsch (.F.) zurück.
Wenn keine ON ERROR-Routine aktiv ist und die Satz- bzw. Dateisperre erfolglos ist, wird eine entsprechender Warnmeldung angezeigt (z.B. "Satz wird bereits von anderem Benutzer benutzt"). Führt jedoch eine Funktion eine Sperre aus, wird die Warnmeldung nicht angezeigt, und die Funktion gibt falsch (.F.) zurück.
TO AUTOMATIC
Ist SET REPROCESS TO AUTOMATIC (oder SET REPROCESS TO -2), führt FoxPro die Satz- bzw. Dateisperre auf unbestimmte Zeit aus. Währenddessen wird die Systemmeldung "Versuche zu sperren... mit ESC abbrechen" angezeigt. Wird der Satz bzw. die Datei zur Sperrung freigegeben, während Sie warten, wird die Sperre ausgeführt und die Systemmeldung gelöscht. Erfolgt die Sperre mit einer Funktion, wird wahr (.T.) zurückgegeben.
Wenn keine ON ERROR-Routine angegeben ist und Sie bei Anzeige der Systemmeldung ESC drücken, erscheint eine entsprechende Warnmeldung (z.B. "Satz wird bereits von anderem Benutzer benutzt"). Erfolgt die Sperre jedoch durch eine Funktion, wird die Warnmeldung nicht gezeigt und falsch (.F.) zurückgegeben.
Wenn eine ON ERROR-Routine angegeben ist und ESC gedrückt wird, wird die Routine ausgeführt. Bei einem Sperrversuch mit einer Funktion wird die ON ERROR-Routine nicht ausgeführt und falsch (.F.) zurückgegeben.
Mit SET LOCK können Sie die automatische Dateisperre aktivieren/deaktivieren. Bei der Ausführung von bestimmten Befehlen sperrt FoxPro normalerweise nicht die Dateien, wenn nur lesend auf eine Tabelle zugegriffen wird. Die folgende Liste enthält die Befehle, die einen Nur-Lese-Zugriff auf eine Tabelle durchführen:
AVERAGE LIST
CALCULATE LABEL
COPY TO REPORT
COPY TO ARRAY SORT
COUNT SUM
DISPLAY (mit einem Bereich) TOTAL
INDEX JOIN (beide Dateien)
Normalerweise kann die Tabelle während der Bearbeitung mit diesen Befehlen noch von anderen Anwendern im Netzwerk benutzt werden. Es ist daher möglich, daß die Tabelle während der Ausführung eines dieser Befehle geändert wird. Wenn Sie z.B. einen Bericht drucken und ein anderer Benutzer einen schon im Bericht enthaltenen Satz ändert, enthält Ihr Bericht dann nicht mehr die neuesten Daten und es können so Inkonsistenzen auftreten.
Der Standard ist SET LOCK OFF.
ON
Um sicherzustellen, daß die neuesten Daten verwendet werden, benutzen Sie SET LOCK ON. Dabei sperren dann die oben aufgeführten Befehle automatisch die Tabelle. Andere Benutzer im Netzwerk können die Tabelle dann nur noch lesen.
Dasselbe Ergebnis erhalten Sie durch Verwendung FLOCK( ) und anschließendem REPORT FORM und UNLOCK. In diesem Fall erfolgt die Dateisperre dann nicht automatisch.
OFF
Mit SET LOCK OFF kann der gemeinsame Zugriff auf Tabellen mit den oben aufgeführten Befehlen aktiviert werden. SET LOCK OFF können Sie benutzen, wenn Sie nicht unbedingt die aktuellsten Daten zur Verfügung haben müssen.
Festlegen, ob mit LOCK() oder RLOCK() das gleichzeitige Sperren mehrerer Sätze möglich ist.
Ist eine Tabelle für gemeinsamen Zugriff im Netzwerk geöffnet, können Sie versuchen, mehr als einen Satz einer Tabelle zu sperren. Entsprechend der Einstellung von SET MULTILOCKS können Sie einen Sperrversuch an einem oder mehreren Sätzen vornehmen.
HINWEIS
Beim Umschalten von SET MULTILOCKS von ON auf OFF oder umgekehrt wird automatisch ein UNLOCK ALL ausgeführt , d.h. alle Satzsperren in allen Arbeitsbereichen werden aufgehoben.
Die Standardeinstellung ist SET MULTILOCKS OFF.
ON
Bei SET MULTILOCKS ON können Sie versuchen, mehrere Sätze zu sperren. Dies ist auch durch Angabe einer Reihe von Satznummern in LOCK() oder RLOCK() möglich.
OFF
Ist SET MULTILOCKS OFF gesetzt, wird beim aktuellen Satz ein einzelner Satzsperrversuch mit LOCK() oder RLOCK() vorgenommen.
Mit FLOCK() wird versucht, eine Tabelle zu sperren. Bei erfolgreichem Sperrversuch einer Tabelle wird wahr (.T.) zurückgegeben. Wenn die Datei oder ein Satz der Tabelle schon von einem anderen Benutzer gesperrt wurde, wird falsch (.F.) zurückgegeben. Es wird jedoch kein Fehler generiert. Aus diesem Grunde können Sie mit FLOCK( ) keine ON ERROR-Routine starten.
Bei erfolgreicher Dateisperre kann die Datei von dem Benutzer zum Lesen und Schreiben benutzt werden, der die Datei gesperrt hat. Für die anderen Benutzer im Netzwerk ist die Tabelle schreibgeschützt.
Eine Tabelle bleibt so lange gesperrt, bis die Sperrung durch den Benutzer, der die Sperrung verursacht hat, wieder aufgehoben wird. Bei Ausgabe von UNLOCK, Schließen der Tabelle oder Verlassen von FoxPro kann die Tabellensperrung wieder aufgehoben werden.
Standardmäßig versucht FLOCK( ) einmal, eine Datei zu sperren. Wenn automatisch ein erneuter Dateisperrversuch ausgeführt werden soll, falls der erste Versuch fehlschlägt, ist SET REPROCESS zu benutzen. Wenn ein Sperrversuch das erste Mal nicht erfolgreich war, wird mit SET REPROCESS die Anzahl der Sperrversuche und die Zeitdauer eines Sperrversuchs bestimmt
<AusdrN> | <AusdrZ>
Wenn Sie keinen Arbeitsbereich oder Aliasnamen angeben, versucht FLOCK(), die Tabelle im aktuellen Arbeitsbereichs zu sperren. Geben Sie die Arbeitsbereichsnummer <AusdrN> oder den Aliasnamen <AusdrZ> an, wenn eine Tabelle in einem anderen Arbeitsbereich gesperrt werden soll.
Mit RLOCK() wird versucht, einen Datensatz oder eine Gruppe von Sätzen zu sperren. RLOCK() ist identisch mit LOCK().
Bei erfolgreicher Sperre wird wahr (.T.) zurückgegeben. Der Benutzer, der die Sperre verursacht hat, hat Lese- und Schreibzugriff auf die gesperrten Sätze. Alle anderen Benutzer im Netzwerk haben Nur-Lese-Zugriff auf die Sätze.
Die Ausführung von RLOCK() garantiert nicht, daß der/die Sperrversuch/e erfolgreich ist bzw. sind. Ein Satz, der schon von einem anderen Benutzer gesperrt wurde, kann nicht gesperrt werden. Ein Satz in einer von einem anderen Benutzer gesperrten Tabelle kann ebenfalls nicht gesperrt werden. Wenn die Sätze nicht gesperrt werden können, wird falsch (.F.) zurückgegeben.
Standardmäßig versucht RLOCK( ) einmal, einen Satz zu sperren. Benutzen Sie SET REPROCESS, um weitere Satzsperrversuche auszuführen, wenn der erste Versuch nicht erfolgreich war. SET REPROCESS bestimmt, wie oft oder wie lange nach einem ersten nicht erfolgreichen Versuch die Satzsperrversuche fortgesetzt werden.
<AusdrN> | <AusdrZ1>
Wenn kein Arbeitsbereich oder Aliasname angegeben wird, versucht RLOCK() den aktuellen Satz der Tabelle im gewählten Arbeitsbereich zu sperren.
Beim Versuch, den aktuellen Satz in einer Tabelle zu sperren, die nicht im gewählten Arbeitsbereich geöffnet ist, ist die Arbeitsbereichnummer <AusdrN> oder der Aliasname der Tabelle <AusdrZ1> anzugeben.
<AusdrZ2>
Um mehrere Sätze zu sperren, ist <AusdrZ2> anzugeben. SET MULTILOCKS muß ON sein und Sie müssen den Arbeitsbereich oder den Aliasnamen der Tabelle angeben, in der mehrere Sätze gesperrt werden sollen. <AusdrZ2> ist eine Liste einer oder mehrerer Satznummern, die jeweils durch Komma getrennt sind. RLOCK() versucht dann, alle angegebenen Sätze zu sperren. Wenn z.B. die ersten vier Sätze einer Tabelle gesperrt werden sollen, muß <AusdrZ2> '1,2,3,4' enthalten.
Sie können mehrere Sätze auch sperren, indem Sie den Satzzeiger auf den zu sperrenden Satz bewegen, RLOCK() oder LOCK() ausführen und dann diesen Vorgang für jeden zu sperrenden Satz wiederholen.
Sind alle in <AusdrZ2> angegebenen Sätze erfolgreich gesperrt, gibt RLOCK() wahr (.T.) zurück. Wenn einer oder mehrere in <AusdrZ2> angegebenen Sätze nicht gesperrt werden können, wird falsch (.F.) zurückgegeben, und keiner der Sätze wird gesperrt. Alle schon bestehenden Satzsperren bleiben jedoch erhalten. Beim Sperren von mehreren Sätzen werden zusätzliche Satzsperren eingefügt, hierdurch werden jedoch keine anderen Satzsperren aufgehoben.
Hinsichtlich der Leistung ist das Sperren der gesamten Tabelle immer schneller als das Sperren selbst einer kleinen Anzahl von Sätzen.
Mit LOCK() können Sie versuchen, einen Satz oder eine Reihe von Sätzen einer Tabelle zu sperren. LOCK() ist identisch mit RLOCK().
Mit SYS(0) werden Rechnername und Rechnernummer als Zeichenkette zurückgegeben, wenn Sie FoxPro im Netz installiert haben. Rechnername und -nummer müssen zunächst von der Netzwerksoftware zugewiesen werden.
Unter Novell wird dies im Login-Script mittels der MACHINE Zuweisung erledigt:
MACHINE =
"%LOGIN_NAME # %P_STATION"
? SYS(0) => "WOODY # 4000E345 # 255"
Wenn Rechnername oder -nummer nicht zugewiesen oder die Netzwerkbenutzeroberfläche nicht geladen ist, gibt SYS(0) eine Zeichenkette zurück, die 15 Leerzeichen, ein Schraffurzeichen (#), gefolgt von einem weiteren Leerzeichen und 0 enthält.
=> " # 0"
Unter WindowsFWG und WindowsNT erhalten Sie den Namen ihres Arbeitsplatzes, die Raute und bei WinWG eine "0", bei WinNT "255".
=> "WOODYS RECHNER # 255"
Mit SYS(2011) wird der aktuelle Satz- oder Dateisperrstatus des aktuellen Arbeitsbereichs zurückgegeben. Im Gegensatz zu FLOCK(), LOCK() und RLOCK() führt SYS(2011) keinen Datei- oder Satzsperrversuch aus.
Die von SYS(2011) zurückgegebene Zeichenkette ist identisch mit der in der Statuszeile angezeigten Meldung (Exklusiv, Satz nicht gesperrt, Satz gesperrt ...). Aufpassen: Die zurückgegebenen Texte sind auch abhängig von der Sprachversion des verwendeten FoxPro Kerns. (Wichtig bei internationalen Programmen!)
SYS(2011) gibt "Exklusiv" nur an dem Rechner zurück, von dem aus die Tabelle exklusiv geöffnet wurde, und "Satz gesperrt" auch nur an dem Rechner, von dem aus der Satz gesperrt wurde.
UNLOCK hebt eine oder mehrere Satzsperre(n) oder eine Dateisperre der aktuellen Tabelle/.DBF, einer Tabelle in einem anderen Arbeitsbereich oder von Tabellen in allen Arbeitsbereichen auf. Satz- und Dateisperren bei Tabellen können nur von dem Benutzer wieder aufgehoben werden, der die Sperren gesetzt hat. Für alleinigen Zugriff geöffnete Tabellen können mit diesem Befehl nicht freigegeben werden.
Bei Verwendung von UNLOCK ohne zusätzliche Argumente wird eine Satzsperre (bzw. Sperren mehrerer Sätze) oder eine Dateisperre der Tabelle im aktuellen Arbeitsbereich aufgehoben.
IN <AusdrN> | <AusdrZ>
Wenn kein Arbeitsbereich oder Alias angegeben ist, wird mit UNLOCK eine Satzsperre (bzw. Sperren mehrerer Sätze) oder eine Dateisperre einer Tabelle des aktuellen Arbeitsbereiches aufgehoben. Zur Freigabe einer Satzsperre bzw. einer Dateisperre einer Tabelle in einem anderen Arbeitsbereich ist dessen Nummer <AusdrN> oder der Tabellenalias <AusdrZ> anzugeben.
ALL
ALL hebt alle Satz- oder Dateisperren in allen Arbeitsbereichen auf.
EXCLUSIVE
EXCLUSIVE öffnet eine Tabellendatei für alleinigen Zugriff in einem Netzwerk, auch wenn SET EXCLUSIVE auf OFF steht.
SHARED
Geben Sie SHARE an, um eine Tabelle für den gemeinsamen Zugriff im Netzwerk zu öffnen. SHARE erlaubt Ihnen, eine Tabelle für den gemeinsamen Zugriff zu öffnen, auch wenn SET EXCLUSIVE auf ON ist.
NOUPDATE
Die Angabe von NOUPDATE verhindert Änderungen an einer Tabelle.
Rückgabe von wahr (.T.), wenn Sie FoxPro/LAN, die Netzwerkversion von FoxPro, benutzen.
Alte Funktion, nur aus Kompatibilität vorhanden. Seit FoxPro 2.5 immer .T. (Unter FoxBase, FoxPro1 und FoxPro2 gab es gesonderte SingleUser und MultiUser Versionen)
Eine verbesserte NETWORK() Funktion könnten Sie so realisieren:
**********************************
FUNCTION IsNetwrk
**********************************
PRIVATE ALL LIKE l*
lcTempName =
SUBSTR(SYS(2015),3)+".DBF"
CREATE TABLE (lcTempName) (Schrott C(1))
USE (lcTempName) SHARED
llTest = "NICHT" $ UPPER(SYS(2011))
USE
DELE FILE (lcTempName)
RETURN llTest
Diese Funktion macht sich zu nutze, daß eine Datei trotz Angabe von SHARED immer im Exklusiv Modus geöffnet wird, wenn keine Netzwerkunterstützung vorhanden ist (SHARE, NETX usw.)
Weitergehende Informationen
Bei der Erstellung dieser Unterlagen haben mir geholfen:
FoxPro Onlinehilfe (!)
Novell 3.x System Administrator Guide
FoxPro 2.5 Advanced Developers Handbook
von Pat Adams & Jordan Powell
Brady Publishing, ISBN 0-13-325341-4
MSDN (MicroSoft Developer Network CD
So ziemlich alle Informationen, die Microsoft so hortet, fein säuberlich auf CD gepresst. Alle 3 Monate neu, und eine wahre Fundgrube an Informationen
CompuServe
Die FoxPro Foren: FoxForum, FoxUser, MSCE, MSCESYS
und natürlich ungezählte Stunden Try and Error....
Netzwerk Libraries:
Um weitergehende Informationen und Einstellungen im Netzwerk vorzunehmen, ist die Verwendung einer Zusatzlibrary fast unumgänglich.
Feststellen der eingeloggten User,
deren Login-Id, Login-Datum/Uhrzeit, Stationsnummer.
Lesen/Setzen der Server Uhrzeit und Datum
Verzeichnisse anlegen, umbenennen, löschen
Rechte abfragen und vergeben,
LaufwerkMAPpings setzen
Transaction Unterstützung,
DruckerQueues erstellen, abfragen, abändern
Netzwerk-Messages versenden
Semaphoren Verwaltung (eine Art netzwerkweite Variablen)
Bindary Daten lesen und schreiben
usw.
Alle hier aufgeführten Zusatztools unterstützen jeweils FP/DOS und FP/WIN.
FPNet
RORY Data, Inc
Komplett in deutsch
Vertrieb: ProLib GmbH
NetLib
Pinnacle Publishing
Englisch
Vertrieb: ProLib GmbH, Ing.Büro Voller
GPLib
George Sexton
Englisch / Deutsch
Vertrieb: dFPUG
Grundlagen der netzwerkfahigen Programmierung
(c)1994 Jurgen Wondzinski