Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Socket Server ohne Threads
Gehe zu Seite Zurück  1, 2, 3  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
28398



Anmeldungsdatum: 25.04.2008
Beiträge: 1917

BeitragVerfasst am: 09.12.2012, 01:52    Titel: Antworten mit Zitat

stevie1401 hat Folgendes geschrieben:

Ich weiß beim besten Willen nicht wie ich die NICHT benutzen sollte, denn irgendwie müssen die Spielernamen, Tische etc. gehandelt werden.
Dies kann m.E. nur global gemacht werden. Dies wäre auch beim schreiben in eine Datenbank nicht anders. Auch dort würde es sofort E/A Fehler geben,
sobald mehrere Clients darin lesen wollen.
Ich wüßte also nicht einmal im Ansatz wie ich einen Server schreiben kann, der Daten on the fly bearbeitet und verwalten muß, damit er mit TSNE funktioniert.

Bei sauberem Programmdesign ist wenig bis kein globaler Zustand vorhanden. Der wird früher oder später immer zu einem großen Problem, wie du ja jetzt selbst siehst.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 09.12.2012, 10:00    Titel: Antworten mit Zitat

Lol, eine sehr konstruktive Antwort^^
Ich habe nie behauptet ein guter Programmierer zu sein. Im Gegenteil. Ich mache alles über try und error, da ich weder Informatik noch sonst etwas in der Richtung gelernt habe.
Programmieren habe ich mir selbst beigebracht und ich habe auch leider keine Gelegenheit mal einen Programmierkurs zu machen, da es sowas in unserer Gegend nicht gibt.

Wie weit man mit "Versuch macht klug" kommt, kannst du hier sehen:
www.doko-lounge.de
Um dieses Projekt geht es übrigens auch in diesem Thread.
Dort "treffen" wir uns inzwischen täglich und das Spielen klappt - bis auf manchen serverseitigen Rausschmiss, 1a.
Das finde ich eigentlich für einen Anfänger gar nicht mal so schlecht zwinkern
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
28398



Anmeldungsdatum: 25.04.2008
Beiträge: 1917

BeitragVerfasst am: 09.12.2012, 17:15    Titel: Antworten mit Zitat

Ich habe nie eine Aussage über deine Fähigkeiten treffen wollen. Großer globaler Zustand ist jedoch de-facto ein Designfehler, der sich jedoch meistens relativ einfach eliminieren lässt, aber meistens gar nicht erst auftaucht, wenn man bestimmte Designmuster nutzt (zugegebenermaßen sind viele von denen in Freebasic noch recht mühselig, da Vererbung nach meinem Kenntnisstand erst noch kommt), wie z.B. MVC (Model-View-Controller), welches sich – behaupte ich einfach mal – sicher auch in dein Projekt prima integrieren würde.

Unterm Strich eliminieren die meisten Patterns nicht nur globalen Zustand, sondern erfordern aktiv eine saubere Modularisierung und führen somit bei stringenter Umsetzung zwangsläufig zu saubererem, stabilerem und besser handhabbarem Code.

Dafür muss man auch nicht studieren oder professionell programmieren - nur machen und reflektieren. Wenn du dir deine Situation bzw. die deines Projekts anschaust, siehst du, dass du zwar grundsätzlich dein Pflichtenheft (Doko-Server und -Client) erfüllt hast, aber die Codebase Probleme hat (wie in diesem Thread deutlich wird). Das zeigt: Mit Trial and Error kommt man oft zum Ziel, aber zu welchem Preis? Oftmals durch eine unsaubere Codebase, die schwer zu warten und zu erweitern ist.
Jetzt ist also der Zeitpunkt gekommen ein Refactoring durchzuführen, bevor du versuchst weitere Funktionalität zu implementieren. Beim Refactoring gehen viele Leute z.B. so vor, dass sie sich ihre Codebase anschauen und danach ein großes Blatt Papier nehmen. Darauf wird dann eine UML-artige Struktur (Objekte, ihre Eigenschaften und Verknüpfungen) entworfen, die dann erstmal in Form von Interfaces (also Objektdefinitionen ohne Implementierung) notiert wird. Dabei fällt dann oft das eine oder andere Detail auf, welches so nicht gut implementierbar ist, wo also bspw. eine Ebene Indirektion zu viel oder zu wenig auftritt. Je nach Erfahrung kann schon der erste Entwurf gut sein, manchmal werden aber auch eine handvoll benötigt.
Danach wird die vorhandene Codebase gedanklich verworfen und erstmal die Verknüpfungen zwischen den Objekten implementiert, das ist idR. Funktionalität die weitestgehend mit Fleischcode nix zu tun hat. Darauf aufbauend ist es oft nur eine Sache von Stunden die vorhandene/sichtbare Funktionalität zu re-implementieren anhand der alten Codebase.
Am Ende sollte man eine sauber modularisierte und nach Designpatterns strukturierte, gut dokumentierte Codebase haben, die sich leicht und problemlos erweitern lässt.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
MilkFreeze



Anmeldungsdatum: 22.04.2011
Beiträge: 116

BeitragVerfasst am: 09.12.2012, 19:16    Titel: Antworten mit Zitat

Soso... Interfaces sind also "Objektdefinitionen" ohne Implementierung...

warum das gleich mehrfach falsch ist.... ach, lassen wir das...
_________________
Milch ftw grinsen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
28398



Anmeldungsdatum: 25.04.2008
Beiträge: 1917

BeitragVerfasst am: 09.12.2012, 19:44    Titel: Antworten mit Zitat

So kann man sich das schon vorstellen, ja. Das das in Programmiersprachen, die Interfaces als Sprachfeatures bieten (Ich glaube Java hat das und PHP5 hat das auch?), natürlich etwas anders.

Letztendlich läuft es beim Konzept Interface trotzdem darauf hinaus, dass ich definiere, was für Eigenschaften und Methoden ein bestimmte Art von Objekten (mindestens) hat. In Freebasic kann ich das repräsentieren, indem ich einen UDT habe, der Methoden und Attribute ohne konkrete Implementierung definiert. Die Implementierung liefert man dann später nach, wenn man sieht, dass die ausgedachten Interfaces miteinander funktioneren können|werden.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
MilkFreeze



Anmeldungsdatum: 22.04.2011
Beiträge: 116

BeitragVerfasst am: 09.12.2012, 20:41    Titel: Antworten mit Zitat

In Objekt-orientierter Programmierung sind Interfaces lediglich Sammlungen von Methoden-Definitionen. Interfaces dürfen keine Attribute haben (woran sich AFAIK nur ABAP nicht hält) und können nicht instantiiert oder geerbt werden. Deswegen sind es auch keine Objektdefinitionen - denn Objekte sind Instanzen von Klassen. Moment... die können nicht geerbt werden? Ja, aber sie können Implementiert werden. Was der Unterschied ist, wird deutlich wenn man sich Mehrfachvererbung und die Probleme damit anguckt.

Freebasic kann übrigens Vererbung - aber lustigerweise keine Interfaces. lächeln

Wenn du von Klassen oder UDTs ohne Implementierung sprichst, dann stell sicher, dass du klarstellst das du das auf der Code-Ebene meinst und nicht von OOP sprichst. Denn in deinem vorherigem Post war der Kontext recht unzweifelhaft OOP - und dann wäre dein halber Post schlichtweg Falsch.

Wie man ohne Missverständnisse das bezeichnet, was du meinst... hmm... da fällt mir leider auch nichts ein. Zumal ich die Vorgehensweise etwas... ähm... kreativ finde. Warum nicht einfach ein stinknormales Software-Design schreiben und UML für deine "Interfaces" (*Hust*) nehmen? Ich meine, wo ist das Problem? Selbst für ne bestehende Anwendung kann ich problemlos noch Nachträglich ein DV-Konzept/Design schreiben und die Anwendung entsprechend anpassen, wenn ich im Konzept Verbesserungen einfließen lasse.

Und wenn ich mit dem Konzept/Design fertig bin, erst dann schreibe ich die erste Zeile Code - das beinhaltet auch Klassen- bzw UDT-Definitionen

Übrigens: Welches Design-Pattern kann man denn in FreeBASIC nicht umsetzen?
_________________
Milch ftw grinsen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
28398



Anmeldungsdatum: 25.04.2008
Beiträge: 1917

BeitragVerfasst am: 09.12.2012, 21:01    Titel: Antworten mit Zitat

Ahhhhh, Haarspalterei ohne Alternativvorschläge grinsen — Gut, dann bin ich raus.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
MilkFreeze



Anmeldungsdatum: 22.04.2011
Beiträge: 116

BeitragVerfasst am: 10.12.2012, 00:01    Titel: Antworten mit Zitat

Magst du mir wenigstens noch auf meine Frage antworten? lächeln
_________________
Milch ftw grinsen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 07:25    Titel: Antworten mit Zitat

@RWK
Du schriebst:
Das klappt deswegen, weil ich mich nicht mehr in der CallBackroutine von TSNE befinde. Darum auch mein Umweg aus der TSNEPlay_Message Sub..die ja das Callback von TSNE bei Dateneingang ist....einfach die Nachricht an eine eigene Sub weiterzuleiten.
Moment mal...
Deine Sub checkMessage() IST doch in der Sub TSNEPlay_Message. Deshalb müsstest du eigentlich auch noch im geschlossenen Thread oder Mutex oder was auch immer das ist, sein.
Genau das hatte ich auch schon mehrfach probiert, allerdings aus der folgender Sub:
Code:

Sub TSNE_NewData(Byval V_TSNEID As Uinteger, Byref V_Data As String, Byval V_CallBackPtr As Client_Type Ptr)

  Dim As String MessageFromClient,ClientIpp
  Dim As Uinteger ClientId
  MessageFromClient=v_data

  ClientId=V_TSNEID
  ClientIpp= V_CallBackPtr->V_IPA
  If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub





  With *V_CallBackPtr

  .V_Data += V_Data
  'Print "[CLIENT] DATA: " & V_TSNEID & " " & .V_IPA & "   DataLen:"; Len(.V_Data)
  'Nur zu dem clienten senden, vond em wir daten empfangen haben
  ' TSNE_Data_Send(V_TSNEID, "Habe daten von dir empfangen!")
  ' TSNE_Data_Send(V_TSNEID, MessageFromClient)
  'print MessageFromClient
  'zu allen clienten senden
  'SendToAll("Hab von " & .V_IPA & " datenempfangen!")
  'print messagefromclient


  check_Client_Nachricht(ClientId,MessageFromClient,ClientIpp)   '<<----hier werden ALLE Nachrichten Dokomäßig verarbeitet.




  .V_Data = ""

  End With

End Sub


...und das soll ja angeblich zu Chrashes führen....
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 10.12.2012, 09:50    Titel: Antworten mit Zitat

@RWK ne .. das is nicht richtig ... @stevie1401 richtig .... Ein Thread endet nicht damit, das man eine unter-sub oder andere funktion aufruft.

Mann kann dies damit vergleichen, das man pro verbindugn ein neues programm startet. Jedes Programm representiert dadurch einen eigenen Thread und handelt eine einzelne verbindung. damit die Programme (Threads) auch auf gemeinsame Resourcen zugreifen können, gibt es eben die möglichkeit (und das geht nru bei threads, und nicht bei realen mehrfach gestarteten programmen) via shared variablen informationen für alle threads verfügbar zu machen.

Allerdings, da diese threads quasi parallel laufen, muss man dafür methoden einführen, die den gleichzeitigen zugriff auf eine "globale" (shared) variable schützen.

Und, dies wird eben via "Mutexe" gemacht.

@stevie1401 ... bezüglich deinem code:
Code:
...
  ClientId=V_TSNEID
  ClientIpp= V_CallBackPtr->V_IPA
  If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub


hier ist die reihenfolge nicht richtig.
du prüfst erst nachdem du auf die Variable V_IPA zugreifst, ob der Speicherbereich existiert. Sollte nicht erst geprüft werden, ob der speicher existiert, bevor man darauf zugreift? zwinkern
Code:
...
  ClientId=V_TSNEID
  If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub
  ClientIpp= V_CallBackPtr->V_IPA


so hier?!.

Im idealfall macht man es dann folgendermassen:
Code:

Sub TSNE_NewData(Byval V_TSNEID As Uinteger, Byref V_Data As String, Byval V_CallBackPtr As Client_Type Ptr)
If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub
'...
End Sub

Sofort nach dem einspringen in das callback, wird geprüft, ob der speicher existiert. wenn dem nicht so ist, gab es einen fehler, der auch später noch existieren wird. (der speicher wurde nie erzeugt, und wird es später auch nie werden, da dies nur in TSNE_NewConnection gemacht wird.)

Daher sollte diese prüfung zu aller erst gemacht werden. erst danach kann dann alles andere erfolgen.

Das folgende ist auch problemlos machbar.
Code:

'...
 check_Client_Nachricht(ClientId,MessageFromClient,ClientIpp)   '<<----hier werden ALLE Nachrichten Dokomäßig verarbeitet.
'...


Sobald jedoch irgend wo in "check_Client_Nachricht" oder in einer sub / function innerhalb von dieser ein zugriff auf globale variablen erfolgt, müssen diese mit einem MutexLock/Unlock umklammert werden.

DANN, gibt es geschützt bereiche, die sich nicht gegenseitig beeinflussen können.


MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 10:49    Titel: Antworten mit Zitat

Ok, ich denke, das habe ich verstanden.
Ich konnte mit dem Code:
Code:

If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub

nichts anfangen, aber ok, das ist ja kein Problem das zu ändern.
Also das mit dem mutexlock und unlock klappt wirklich nicht. Dies bei jeder globalen Variable zu machen wäre echter Irrsinn bei meinem Code.
Aber ich habe eine andere Idee.

Es gibt ja noch die Hauptschleife (siehe REM)

Nehmen wir mal an, ich mache aus dem String MessageFromClient eine Shared Variable.
Code:

Sub TSNE_NewData(Byval V_TSNEID As Uinteger, Byref V_Data As String, Byval V_CallBackPtr As Client_Type Ptr)

 If V_CallBackPtr = 0 Then TSNE_Disconnect(V_TSNEID): Exit Sub

' Ich kann hier kein Mutexlock(G_ClientMux) machen, weil ich nicht weiss was G_ClientMux hier ist

    'MessageFromClient ist Dim Shared

    MessageFromClient=v_data

  ClientId=V_TSNEID    'auch dim shared
  ClientIpp= V_CallBackPtr->V_IPA    'auch dim shared
 





  With *V_CallBackPtr

  .V_Data += V_Data
  'Print "[CLIENT] DATA: " & V_TSNEID & " " & .V_IPA & "   DataLen:"; Len(.V_Data)
  'Nur zu dem clienten senden, vond em wir daten empfangen haben
  ' TSNE_Data_Send(V_TSNEID, "Habe daten von dir empfangen!")
  ' TSNE_Data_Send(V_TSNEID, MessageFromClient)
  'print MessageFromClient
  'zu allen clienten senden
  'SendToAll("Hab von " & .V_IPA & " datenempfangen!")
  'print messagefromclient


 




  .V_Data = ""

  End With

End Sub


Hier die Hauptschleife

Code:

Dim RV As Integer = TSNE_Create_Server(TServerID, ServerPort, 500, @TSNE_NewConnection)

If RV <> TSNE_Const_NoError Then
  Print "[SERVER] [FEHLER] " & TSNE_GetGURUCode(RV)
  End 0
End If
Print "[SERVER] OK!"

'HAUPTSCHLEIFE
Do
  Sleep 10, 1
if MessageFromClient<>"" then
  check_Client_Nachricht(ClientId,MessageFromClient,ClientIpp)   '<<----hier werden ALLE Nachrichten Dokomäßig verarbeitet.
  MessageFromClient=""
end if

Loop Until Inkey() = Chr(27)


Mir ist klar, dass - sollte ich dies so machen dürfen- Nachrichten verloren gehen können.
Dies wäre aber nicht dramatisch, was den Spielablauf angeht.
Schlimmstenfalls würde eine Chatnachricht verlorengehen.

Wäre dieses Beispiel machbar?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 10.12.2012, 11:19    Titel: Antworten mit Zitat

Ich habe das gefühl, das dir das prinzip von Mutexe noch nciht ganz klar ist.

Aber, erstmal zu dem V_CallBackPtr ...

Diese Variable ist (tsne abhängig) einfach nur ein Pointer, also ein zeiger, auf einen vom Programmierer optional definiertem Speicherbereich.

je nachdem, wie tsne eingesetzt wird, kann (muss aber nicht) man einen Speicher erzeugen, den man über die funktionen von tsne unverändert übertragen kann.

Vergleichbar mit einem Postboten, den man beauftragt einen brief an seinem gegenüber zu senden. Bei sich zu hause hat man einen aktenschrankt, in dem entsprechende akten liegen, welche den empfänger identifizieren.

sendet der gegenüber nun eine antwort zurück, dann kommt wieder ein postbote zu einem zurück. irgend jemand, denn man ja nicht kennt.

Um jetzt herauszufinden, von wehm dieser brief kommt, hat der postbote wiede diesen zettel dabei, den er nur bei diesem empfänger mit hat. alle anderen haben einen eigenen zettel.

auf diesem steht dann etwas drauf, das man frei definieren kann.

dieser zettel ist mit dem V_CallBackPtr gleichzusetzen.

man kann ihn nutzen, muss aber nicht. wenn man es aber macht, dann wird dieser zettel immer mitgebracht, und man kann ihn auswerten / nutzen.

Da in dem von dir genutztem code-beispiel dieser verwendung findet, gehe ich einmal stark davon aus, das diese technik der "gegenstellen-identifikation" genutzt wird.

V_CallBackPtr ist also der zettel. Dirt steht die adressedes speicherplatzen drin (Ptr = Pointer), der auf die akten (V_IPA, V_Data, ...) Zeigt. Man kann also direkt darauf zugreifen, ohne vorher nach der Akte (z.B. mit Do Loop / For Next) suchen zu müssen.

Es ist nur eine vereinfachung.


Bezüglich dem Mutex.

Nun ... ich hatte schonmal versucht dir das per PM zu erklären, versuche es aber hier nochmal etwas anders.

Die Variable "G_ClientMux" hält eine Identifikationsnummer zu einem Mutex. Sie hat nur diese aufgabe. Sie hat nichts mit eienr verbindugn selbst zutun.

Diese Mutex-ID-Nummer ist nötig, damit das Betriebssystem weis, um Welches Mutex es sich handelt.
Es können mehr als nur ein Mutex erzeugt werden. darum benötigt man eine Variable, welche die ID des erzeugten Mutex speichert.
Code:
MyMutexID = MutexCreate()

G_ClientMux ist demzufolge identisch mit MyMutexID

Diese Variable muss Shared sein (was sie sicher auch ist).

Dadurch kann von jedem Thread aus darauf zugegriffen werden. Wenn nun ein Thread irgend eine andere Globale Variable ändern möchte, dann müssen allen anderen Threads mitgeteilt werden, das sie warten müssen, wenn sie auch auf diese Variable zugreifen möchten.

Das kann man mit den befehlen MuteLock(<ID>) und MutexUnLock(<ID>) realisieren.

Alles, was zwischen diesen beiden Befehlen steht, dessen <ID>'s identisch sind, wird geschützt.

beispiel:
Code:

'hier wird zuerst eine globale variable erzeugt, welche die ID des neu erzeugten Mutex speichert
Dim Shared MyMutexID as Any Ptr

'eine allgemeine globale variable, die wir verändern möchten.
Dim Shared GlobaleVariable as UInteger

'unser thread (vergleichbar mit den callbacks von TSNE)
Sub MyThread()
'wir durchlaufen 100x die änderung der variable
for x as uinteger = 1 to 100
    'da von mehreren threads auf diese variable zugegriffen wird, müssen wir diese variable schützen.
    'das können wir realisieren, indem wir ein mutex sperren, das wir erzeugt haben.
    'indem wir das mutex sperren, zeigen wir dem betriebssystem an, das andere threads beim aufruf des selben befehls (MutexLock), solange warten müssen,
    'bis der thread, welcher das mutex zuerst gesperrt hat, wieder Entsperrt (MutexUnLock)
    MutexLock(MyMutexID)
        'nach der sperre, können wir die globale variable (oder globale variablen) abändern / darauf zugreifen
        GlobaleVariable += 1
    'nach dem zugriff, können wir die sperre wieder lösen. Ab jetzt können andere threads darauf zugreifen.
    MutexUnLock(MyMutexID)
next
End Sub

'nach dem programstart muss zuerst das mutex erzeugt werden.
MyMutexID = MutexLock()
'danach starten wir testweise 3 threads.
threadcreate(@MyThread)
threadcreate(@MyThread)
threadcreate(@MyThread)
'und warten bis zum esc druck.
do until inkey() = chr(27)
    sleep 100, 1
loop
end


ich hoffe, das der code und die beschreibung hilft.

wie schon beschrieben, ist ein Mutex-ID nur für das Betriebssystem wichtig. Man kann diesem signalisieren, das ab dem Lock, andere threads warten müssen, bevor sie auch mit der variable arbeiten dürfen.


man muss nicht zwingend jede variable oder ejden zugriff einzeln abschrimen. man kann auch mehrere zugriffe damit schützen.

Code:

mutexlock(...)
   gloablevariable1 = variable2
   variable3 = globalevariable + 10
   variable4 = globalevariable3 + 100 + 10 + 1
mutexunlock(...)


es muss also nicht zwingend so aussehen:
Code:

mutexlock(...)
   gloablevariable1 = variable2
mutexunlock(...)
mutexlock(...)
   variable3 = globalevariable + 10
mutexunlock(...)
mutexlock(...)
   variable4 = globalevariable3 + 100 + 10 + 1
mutexunlock(...)



MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 12:06    Titel: Antworten mit Zitat

Doch doch, ich befürchte, ich habe das einigermaßen begriffen.
Und somit kann man sagen, dass man in der Sub TSNE_NewData() keinen Mutex schützen kann,richtig?
Das bedeutet, dass die Nachricht, die in die Sub TSNE_NewData() reingeht, nicht geschützt werden kann, um sich so eine Kopie davon machen zu können.
Und es bedeutet dann wohl auch, dass ich die Nachricht, weil ich sie nicht Threadsicher schützen kann, nicht in der Hauptschleife weiterverarbeiten kann.

Oder gibt es irgendeine Möglichkeit meinen gottverdammten String in die Hauptschleife zu bekommen?
Mehr will ich doch überhaupt nicht.

Es liegt sicherlich an der Art meiner Programmierung, aber so kann ich TSNE wirklich für mein Projekt vergessen.
OK, das hätten wir dann ja nun.
Kann mir jemand ein Beispiel für WSAAsyncselect oder WSAEventselect in Freebasic geben?
Vielen Dank.


Zuletzt bearbeitet von stevie1401 am 10.12.2012, 12:20, insgesamt einmal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 10.12.2012, 12:12    Titel: Antworten mit Zitat

also, laut deiner aussage gerade, muss ich leider gegenteiliges behaupten. ich glaube, du hast es doch nicth so richtig verstanden zwinkern

Du kannst durchaus ein Mutex anwenden, in der Sub. Und das Problemlos.

Übrigens, schützt man nicht ein Mutex, sondern man schützt einen Thread vor einem anderen MITHILFE von Mutexe.


MfG
TPM

PS: ich werde mal versuchen das grafisch aufzuzeigen.
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 12:25    Titel: Antworten mit Zitat

Danke für deine Mühe, aber das brauchst du wirklich nicht.
Ich möchte einfach nur den String MessageFromClient aus der Sub TSNE_NewData() in die Hauptschleife bekommen.
Langt mir vollkommen.
Wenns gehen sollte, dann schreibe mir bitte die Befehlscodezeile hier rein. Wenns nicht geht, auch ok.
Wie komme ich an die MutexID, um Mutexlock in der Sub TSNE_NewData( machen zu können. Mehr brauche ich doch gar nicht. Ich will einfach nur diesen String bearbeiten.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 10.12.2012, 12:35    Titel: Antworten mit Zitat

ganz oben (global) im programm einfügen
Code:

Type MSG_Type
    V_Next as MSG_Type Ptr
    V_TSNEID as UInteger
    V_Data as UInteger
End Type
Dim Shared G_MSGF as MSG_Type Ptr
Dim Shared G_MSGL as MSG_Type Ptr
'...


ersetzen
Code:

'...
Sub TSNE_NewData(Byval V_TSNEID As Uinteger, Byref V_Data As String, Byval V_CallBackPtr As Client_Type Ptr)
MutexLock(G_ClientMux)
If G_MSGL <> 0 Then
    G_MSGL->V_Next = CAllocate(SizeOf(MSG_Type))
    G_MSGL = G_MSGL->V_Next
Else
    G_MSGL = CAllocate(SizeOf(MSG_Type))
    G_MSGF = G_MSGL
End if
With *G_MSGL
    .V_TSNEID = V_TSNEID
    .V_Data = V_Data
End With
MutexUnLock(G_ClientMux)
End Sub
'...



hauptschleife
Code:

'...
Dim TPtr as MSG_Type Ptr
Do Until InKey() = Chr(27) 'oder wie auch immer die schleife aussieht
    '...
    MutexLock(G_ClientMux)
    If G_MSGF <> 0 Then
        TPtr = G_MSGF
        With *TPtr
            Verarbeite_Nachricht(.V_TSNEID, .V_Data)
        End With
        G_MSGF = TPtr->V_Next
        DeAlloctae(TPtr)
    End If
    MutexUnLock(G_ClientMux)
    '...
    sleep 1, 1
Loop


So in etwa müsste das klappen.


MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 12:41    Titel: Antworten mit Zitat

WOW, cool lächeln
Ich vermute mal ich muss in der neuen Sub TSNE_NewData() NICHTS machen, richtig?
Und der String, den ich verarbeiten möchte ist in der Hauptschleife .V_Data, oder?

Vielen Dank lächeln
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 10.12.2012, 12:44    Titel: Antworten mit Zitat

richtig.

allerdigns, zerstört es die kompletten features die TSNE mitsich bringt. (Asynchronizität und parallelität)

Dadurch wird der gesammte ablauf serialisiert, was eigentlich absolut schädlich für einen server bzw. einer server-client kommunikation ist.

Code:

Verarbeite_Nachricht(.V_TSNEID, .V_Data)


ist deine "verarbeiten" sub. ...
.V_TSNEID ist die Verbindungsnummer des clienten welcher die nachricht gesendet hat.
.V_Data enthält die daten vom clienten.


MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 10.12.2012, 12:53    Titel: Antworten mit Zitat

Jo, das verstehe ich ja auch. Aber gerade die Asynchronizität und Parallelität verhindert ja, dass ich ohne Chrashes meine Daten heile "nach Hause kriege".
Und wenn ich in meiner VerarbeitungsSub geschätzte 200-400x lock und unlock machen muss (was irre Fehlerquellen verursachen kann), erkenne ich keinen Gechwindigkeitsvorteil mehr.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
stevie1401



Anmeldungsdatum: 04.07.2006
Beiträge: 133

BeitragVerfasst am: 21.12.2012, 22:29    Titel: Antworten mit Zitat

Also ich habe das jetzt ungefähr so gemacht, wie du es vorgeschlagen hast, Puppet, nun tritt oft folgendes auf:
IDs werden DOPPELT vergeben (an den selben Spieler). Der Spieler ist dann doppelt im Spiel.
Obwohl Spieler zu 100% online sind, haben sie keine Verbindung mehr zum Doko-Server - was weder die Clients noch der Server merken und es keinen Meldungen diesbezüglich gibt.
Die Clients sind weiterhin per WSAAsyncselect mit dem Server verbunden.
Kann es daran liegen?

Selbst wenn ein Spieler, der doppelt drin ist, sich wieder ordnungsgemäß mit closesocket abmeldet (dann ist er erst mal weg) und er sich wieder neu anmeldet, so ist er dennoch gleich wieder doppelt zu sehen.

Was bewirkt der Befehl "DeAlloctae(TPtr)"?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Gehe zu Seite Zurück  1, 2, 3  Weiter
Seite 2 von 3

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.

 Impressum :: Datenschutz