Zitat von
.chicken:
Hab im Inet was über ein Protokoll gelesen, dass die Kommunikation zwischen Server und Client regelt.
Damit ist doch nichts anderes gemeint, als das auswerten von Textnachrichten, die zwischen Server und Clients hin und hergeschickt werden oder?
Nun ja, wie soll ich das beantworten? Ich weiß doch nicht über
welches Protokoll Du
was gelesen hast. An sich geht es jedenfalls mit Sicherheit in die Richtung, stimmt so aber nicht 100%ig.
Um es einfach und kurz zu sagen, ein Protokoll legt nur fest, wie man kommuniziert. Es gibt zig Protokolle, die Du verwenden kannst, die Teilweise sogar auf einander aufbauen. Nimm einfach
TCP/
IP, dabei handelt es sich keineswegs um ein einziges Protokoll, vielmehr um
TCP over
IP. So steckst Du die Daten, die Du übertragen möchtest einfach in
TCP-Pakete. Diese Pakete wiederum verpackst Du in
IP-Pakete (dort stimmt der Begriff Paket nicht mehr ganz) und verschickst sie.
IP stellt dabei nur sicher, dass irgendwelche Bytes an den Empfänger mit der angegebenen
IP geht. Diese irgendwelchen Bytes werden auf der Empfängerseite dann weiter verwendet. Dort gibt es dann auch die
IP Schicht, die diese Daten empfängt und an die darüberliegende Schicht weiterreicht. Für
IP waren es nur irgendwelche Bytes, für die darüber liegende
TCP Schicht ist es dann aber schon ein
TCP-Paket. Das enthält ein paar Informationen (welches Paket um die Reihenfolge sicherzustellen, welche Checksumme um Übertragungsfehler zu erkennen...) und irgendwelche Nutzdaten (wieder nur Bytes). Für die darüber liegende Schicht gibt es z.B. auch wieder ein Protokoll, dass diese Nutzdaten bekommt und weiter verarbeitet.
Deine Anwendung steht dabei auf der obersten Schicht (schau Dir einfach mal das OSI Modell an). Willst Du also Daten verschicken, läufst Du von oben nach unten und packst für jede Schicht (außer der physikalischen Übertragungschicht) einfach weitere Daten außen rum (die für die jeweilige Schicht benötigt werden).
Auf jeder Schicht könntest Du dann von einem Server und einem Clienten sprechen (ziemlich allgemeine Begriffe). Natürlich kannst Du auch in Deiner Anwendung noch viele weitere Protokolle einbauen, die dann auf dem
TCP/
IP aufbauen. Auch auf jede dieser Schichten könnte dann zutreffen, dass die jeweils einen Client oder Server kennen.
Wichtig ist eigentlich nur, dass für jede Schicht immer Metainformationen (nur für die Schicht wichtig!) und Nutzdaten übertragen werden. Die Nutzdaten interpretiert die Schicht dabei nicht weiter, sondern reicht diese an die nächst höhere Schicht weiter. Ganz oben steht immer etwas, dass nur noch Nutzdaten bekommt und mit denen Arbeitet.
Bei einem Webserver hättest Du auch einen Interpreter, der eine
HTML-Seite rendert. Die
HTML-Seite wird dabei über das Hyper Text Transport Protocol (HTTP) übertragen. Dieses wird durch
TCP-Pakete übertragen. Diese werden über
IP übertragen....
Was für Nutzdaten in der obersten Schicht landen ist egal. Es sind einfach Bytes, die beliebig interpretiert werden können. Hast Du ein Datum von 4 Byte, kann das eine Zahl sein (z.B. ein Integer/Cardinal, ein Single, zwei Word, 4 Byte), es könnten Zeichen sein (4
Ascii Zeichen, 4 UTF-8 kodierte Zeichen, 2 UTF-16 kodierte Zeichen), aber auch alles andere, was in 4 Byte kodiert werden kann. Wie Du was überträgst kannst Du einfach in einem Protokoll festlegen (es sind also Nachrichten, aber nicht zwangsläufig Textnachrichten).
Zitat von
.chicken:
In meiner
Unit "Controller" habe ich die procedures "Call", "Bet", etc.!
Die
Unit "Server" hat den "Controller" in der uses Klausel!
Jetzt muss aber der Server die Clients aktualisieren, wenn zB ein Call ausgeführt wird.
Kann das dem Controller aber nicht sagen, weil der Server ja nicht in seinen uses steht!
Was genau macht denn der Controller? "Call" und "Bet" ist etwas allgemein, es gibt verschiedene Dinge, die Du hier unterscheiden musst. Wurde die Aktion gerade ausgelöst (Clientseitig) oder wurde die Benachrichtigung empfangen, dass ein Spieler eine solche Aktion durchgeführt hat (Clientseitig)? Oder wurde dem Server gerade mitgeteilt, dass ein Spieler eine solche Aktion ausgeführt hat?
So muss der eigentliche Auslöser den Server benachrichtigen, was getan wurde.
Der Server wiederum muss alle Clients benachrichtigen.
Bekommen die Clients eine Benachrichtigung vom Server, müssen sie diese darstellen.
Das alles passiert, wenn ein Bet gemacht wurde, allerdings an drei völlig verschiedenen Stellen. Für alles könnte ein Controller in Frage kommen, der eine Methode "bet" hat (der Name "Bet" ist
imho hier zu aussagelos).
Zitat von
.chicken:
Gibts da ne Möglichkeit? "Über-Kreuz-uses" sollen (laut dem Forum) ja nicht gut sein (und funktioniern eh nicht!?).
Ist (nicht nur laut dem Forum) total schlecht in jeder Hinsicht und sollte immer vermieden werden (die meisten Sprachen verbieten es). In Delphi geht das durchaus, aber ich werde nicht sagen wie (ist sehr einfach, aber da Du es eh nicht verwenden sollst...).
Es gibt immer saubere Alternativen (es geht also immer auch anders)!
Der einfachste Weg ist es immer, dass Du die Units neu aufteilst. Häufig reicht es schon, dass man einen Teil in eine dritte
Unit schiebt, auf die die beiden anderen zugreifen können. Diese dritte
Unit sieht aber dafür die anderen zwei nicht.
In diesem Fall musst Du nur schauen, was alles passieren kann und wer dazu welche Informationen benötigt.
Betrachte ich die Methode Bet, so würde ich sagen, dass die immer dann aufgerufen wird, wenn jmd. etwas setzt. Da würde es mich dann aber stark wundern, dass der Server diese Methode /
Unit kennen muss, denn der Server selbst wird nur benachrichtigt, wenn diese Methode von einem der Spieler aufgerufen wurde (wenn der selber setzt wäre das doch ungewöhlich).
Aber auch den umgekehrten Weg würde ich nicht ganz verstehen, setzt ein Spieler, so würde hier die Methode Bet aufgerufen werden. Diese Methode wird also Clientseitig aufgerufen. Ein Client muss die Server-
Unit gar nicht kennen, sondern sendet über einen
TCP-Client eine Nachricht an den Server. Hier muss also die
Unit Controller nur eine Möglichkeit haben, die Nachricht zu verschicken (oder jmd. zu informieren, was gemacht wurde, so dass dieser jmd. die Nachricht verschickt).
Kommt die Nachricht beim Server an, so muss der alle Clienten darüber Informieren, was eine eigene Methode ist. Dabei muss der Server seine Liste der gemeldeten
TCP-Clienten durchgehen und ihnen eine Nachricht zuschicken. Hier ist nur wichtig, dass über
TCP (oder welche Protokoll auch immer) eine Nachricht versendet wird.
Empfängt jetzt ein Client eine Nachricht, so muss er eine Ereignisbehandlung durchführen. Auch hier sehe ich nicht, dass ein Zugriff auf den Controller nötig wäre. Wo also siehst Du das Kreuz?
Deutlicher gesagt würde ich folgenden Ablauf sehen/modellieren:
- Spieler setzt (Aufruf von "Bet")
- Benachrichtigung des Servers (Aufruf von "NotfiyServer")
- Empfangen der Nachricht durch den Server (Aufruf von "OnServerReceiveMessage")
- Benachritigen aller Clienten/Spieler (Aufruf von "NotifyClients")
- Empfang der Nachricht von einem Clienten (Aufruf von "OnClientReceiveMessage")
- Anzeigen der Änderungen (Aufruf von "Update...")
Die Namen sind jetzt nicht sonderlich gut gewählt, es soll nur anzeigen, dass hier nirgendwo ein Kreis entsteht, ein Überkreuzen ist also nicht nötig (soweit ich nicht irgendwas übersehe).
Zitat von
.chicken:
Edit: Ok, hab nun einfach den Controller ganz weggelassen und das ganze Zeugs direkt vom Server machen lassen! Klappt so super, ist natuerlich nurn bissl mehr Code im Server aber egal
Absolut schlechter Ansatz (entschuldige!). Das mag hier nochmal klappen, aber je größer das Projekt, desto größer auch die Server-
Unit. Wenn Du dort dann etwas finden möchtest.... Ich kann da wirklich nur aus meiner Erfahrung sprechen und muss Dir dringend von solchen Ansätzen abraten. Wie gesagt, es geht immer ohne. Wenn Du da im Moment keinen Weg siehst, können wir gerne drüber reden und ich kann Dir hoffentlich einen zeigen.
Gehst Du aber immer den Weg, den Du gerade gegangen bist, dann führt das einfach zu riesigen Units. Die sind sehr viel schlechter wartbar und fehleranfälliger. Möchtest Du eine bestimmte Funktionalität wiederverwenden, so wird Dir schnell die gesamte
Unit zu groß sein und man neigt zu copy&paste, bei so großen Units kannst Du dabei schnell mal eine wichtige Abhängigkeit (von etwas anderem in der
Unit) übersehen und Du kopierst etwas, dass zwar kompiliert aber totaler Mist ist! Deswegen lieber kleine Units, die eine kleine Aufgabe lösen.
Zitat von
.chicken:
Wenn das Projekt fertig ist wirds eh nochmal komplett überarbeitet, wenn mir dann ne Lösung einfällt änder ichs vielleicht nochmal
Auch nichts wozu ich Dir raten kann. Mein Chef sagt das ständig zu mir, machen wir mal schnell einen Prototyp fertig, schön machen kann man immer noch. Hab früher sogar daran geglaubt! Ganz ehrlich, klappt nie! Dafür gibt es immer viel zu viel zu tun. Gilt nicht nur in einer Firma! Auch Dich wird das nächste Projekt (wenn Du eins findest) schnell mehr reizen (gut, im Job kann man es sich nicht so aussuchen). Alles was Du später schön machen/überarbeiten willst, fließt unfertig und/oder fehleranfällig in das Endprodukt, glaub mir (haben sowas schon verkauft
). Es fehlt immer an allem, was nötig ist um es gleich richtig zu machen, aber da muss man sich trotzdem zu zwingen. Egal wieviel länger es dauert es richtig zu machen, die Zeit holst Du immer wieder rein! Bist Du erstmal fertig ist die Motivation es neu/anders zu machen niedrig. Hast Du nicht von Anfang an sauber modelliert, wirst Du schnell merken was ich schon vorhin sagte, es gibt Abhängigkeiten die Du gar nicht siehst. Da tauscht Du dann an einer Stelle etwas aus, startest die Syntaxprüfung und bekommst sofort andere Stellen, die angepasst werden müssen. Passt Du die an, zieht das wieder Änderungen nach sich. Prüfen ob die erste Anpassung überhaupt korrekt war kannst Du nicht, da Du ja nicht compilieren kannst, solange nicht alles angepasst wurde. Dann irgendwann hast Du etliche Stellen geändert, merkst dass das so nicht geht und hast ein Problem... (klar, es gibt Backups, aber die Motivation sinkt rapide!).
Hast Du gleich sauber gearbeitet, stellt das spätere Anpassen (soweit es überhaupt nötig wird) kein Problem dar. Und glaub mir, dass ist kein erfundenes und übertriebenes Worst-Case-Szenario, sondern so ging es mir damals wirklich regelmässig.
Da findet man nicht mal ebend eine Stelle, die man leicht ändern kann! Häufig passiert sowas zudem aus Zeitdruck heraus. Gibt man dem Druck nach, bekommt man vielleicht noch irgendwas zusammen, das läuft, aber der Nachfolgeauftrag ist dann schon nicht mehr wünschenswert! Da sollen dann eben kleine Änderungen vorgenommen werden, irgendwas Neues rein und Du stehst vor irgendeinem Chaos, dass Du irgendwann mal überarbeiten wolltest und weißt nicht wo anfangen. Damit erhöht sich nur der Aufwand, für das, was Du in der gleichen Zeit packen musst...
Deshalb gilt wirklich, mache alles gleich richtig! Da gibt es diese bekannte Rechnung, dass eine Problem/Fehler während der Planung grob einen Dollar kostet (jeweils um behoben zu werden!), während der Implementierung der Funtion kostet der gleiche Fehler schon 10 Dollar, nach Fertigstellung/Zusammensetzen der Software kostet er 100 Dollar und wenn das Produkt ausgeliefert wurde > 1000 Dollar. Die Zahlen sind hier natürlich symbolisch zu verstehen, lieferst Du ein schlechtes Produkt aus, kann es Dich auch alles kosten (Imageschäden kann man nicht mit Geld beziffern).
Trotzdem stimmen die Relationen der Kosten schon ganz gut, man hat echt schnell eine Verzehnfachung des Aufwands (gefühlt noch viel mehr), wenn man etwas vor sich her schiebt. Das gilt auch für Dinge, die man zu einem bestimmten Zeitpunkt noch nicht berücksichtigt. Je früher man etwas mit einbezieht, desto besser!!!!