PB-NetworkServer/unverständliches Verhalten!?

Fragen und Bugreports zur PureBasic 4.0-Beta.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

PB-NetworkServer/unverständliches Verhalten!?

Beitrag von Toshy »

Guten Abend.
Ich bin zwar noch am testen, aber ich poste schon mal was in der Hoffnung mir kann dazu schon mal jemand was sagen um meine Denkprozesse zu beschleunigen :-)
Erstmal der Code:

Code: Alles auswählen

;
; ------------------------------------------------------------
;
;   PureBasic - Network (Server) example file
;
;    (c) 2003 - Fantaisie Software
;
; ------------------------------------------------------------
;

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf
Global go1.b
Procedure proc_ThreadFuerServerUeberwachung(plcebo)
  port = 6832
Buffer = AllocateMemory(1000)
If CreateNetworkServer(0, port)
  go1 = 1
   ; MessageRequester("PureBasic - Server", "Server created (Port "+Str(port)+").", 0)
    Repeat
     SEvent = NetworkServerEvent()
    If SEvent
      ClientID = EventClient()
      Select SEvent
        Case 1
          ;MessageRequester("PureBasic - Server", "A new client has connected !", 0)
          Debug "neuer Client: "+Str(ClientID)
        Case 2
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a packet !", 0)
          ReceiveNetworkData(ClientID, Buffer, 1000)
          MessageRequester("Info", "String: "+PeekS(Buffer), 0)
        Case 3
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a file via the network !", 0)
          ReceiveNetworkFile(ClientID, "C:\TEST_Network.ftp3")
        Case 4
          ;MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connexion...", 0)
          ;Quit = 1
          Debug "Client getrennt: "+Str(ClientID)
      EndSelect
    EndIf
    Delay(100)
  Until Quit = 1 
   ;MessageRequester("PureBasic - Server", "Click to quit the server.", 0)
   CloseNetworkServer(0)
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf
EndProcedure
Debug "thread erstellen mit Sever"
CreateThread(@proc_ThreadFuerServerUeberwachung(), 0)
Debug "warte auf Server"
Repeat
  Delay(1)
Until go1 = 1
Debug "Verbindungen werden aufgebaut"

port = 6832

While a.l < 600*10
  a = a+1
  If a < 50
ConnectionID = OpenNetworkConnection("127.0.0.1", port)
If ConnectionID
  ;MessageRequester("PureBasic - Client", "Client connected to server...", 0)
  
  ;SendNetworkString(ConnectionID, "An hello from a client !!! :-)")
  
  ;MessageRequester("PureBasic - Client", "A string has been sent to the server, please check it before quit...", 0)
  
  CloseNetworkConnection(ConnectionID)
Else
  MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf
EndIf
Delay(10)
Wend


End   
Es ist so. Ich arbeite viel mit Threads, na ja, versuche es und ich hatte es jetzt einige Zeit lang aufgegeben, da einfach ständig fehler auftraten, die ich einfach nicht kapierte.
Nun ist es so, das ich das Problem mit dem beigelegten PB-Democode auch bekomme, ich mußte ihn natürlich anpassen.
Es wird in einem Thread der Server erstellt und abgeschragt, im Hauptcode werden dann Verbindungen aufgebaut und beendet.
Der Server hat ein größeres Delay(), was verzögerungen bei Volllast oder Bearbeitungsschritte simulieren soll. Nun wird nach und nach eine Verbindung aufgebaut und sofort danch beendet, aber es werden NUR die Verbindungsaufbauten vom Server erkannnt, die Trennungen aber erst, sobald es keine neuen Verbindungen mehr gibt. Es scheint so, als ob nicht erst das "älteste" Event abgearbeitet wird, sondern das letzte bzw. vorrangig die Aufbauten. Warum ist das so? Ist das ein Fehler? Wie sieht es mit den ClientID`S und Sockets aus, wenn eine Verbindung getrennt wird aber noch nicht vom Programm erkannt wird, nun aber einen neue aufgebaut wird, kann diese dann nicht das selbe Socket erhalten bzw. die ID wie eine Vorherige Verbindung!? Dann kommen natürlich zwangsläufig alle Datenbankeinträge durcheinander. Ich werde hier langsam etwas verrückt. Gibt es denn keine Möglichkeit PB "anzuweisen", das zwischendurch auch mal die "Verbindungstrennungen" ausgegeben werden. BEi mir könnte es schon von der Theorie her passieren, das Stundenlang keine einzige Trennung verarbeitet werden kann.

Ach ja, mit Debugger laufen lassen, getestet mit Unicode und Threadsafe beim kompelieren.


Gruß
Toshy
2007
[edit d=07012007 h=1207]
Hier noch mal die Debugausgabe. Man sieht was passiert. 50 Clientaufrufe und immer das selbe. Selbst bei 200 Aufrufen das selbe.
  • thread erstellen mit Sever
    warte auf Server
    Verbindungen werden aufgebaut
    neuer Client: 3875040
    neuer Client: 3875072
    neuer Client: 3875104
    neuer Client: 3875136
    neuer Client: 3875168
    neuer Client: 3875200
    neuer Client: 3875232
    neuer Client: 3875264
    neuer Client: 3875296
    neuer Client: 3875328
    neuer Client: 3875360
    neuer Client: 3875392
    neuer Client: 3875424
    neuer Client: 3875456
    neuer Client: 3875488
    neuer Client: 3875520
    neuer Client: 3875552
    neuer Client: 3875584
    neuer Client: 3875616
    neuer Client: 3875648
    neuer Client: 3875680
    neuer Client: 3875712
    neuer Client: 3875744
    neuer Client: 3875776
    neuer Client: 3875808
    neuer Client: 3875840
    neuer Client: 3875872
    neuer Client: 3875904
    neuer Client: 3875936
    neuer Client: 3875968
    neuer Client: 3876000
    neuer Client: 3876032
    neuer Client: 3876064
    neuer Client: 3876096
    neuer Client: 3876128
    neuer Client: 3876160
    neuer Client: 3876192
    neuer Client: 3876224
    neuer Client: 3876256
    neuer Client: 3876288
    neuer Client: 3876320
    neuer Client: 3876352
    neuer Client: 3876384
    neuer Client: 3876416
    neuer Client: 3876448
    neuer Client: 3876480
    neuer Client: 3876512
    neuer Client: 3876544
    neuer Client: 3876576
    Client getrennt: 3876576
    Client getrennt: 3876544
    Client getrennt: 3876512
    Client getrennt: 3876480
    Client getrennt: 3876448
    Client getrennt: 3876416
    Client getrennt: 3876384
    Client getrennt: 3876352
    Client getrennt: 3876320
    Client getrennt: 3876288
    Client getrennt: 3876256
    Client getrennt: 3876224
    Client getrennt: 3876192
    Client getrennt: 3876160
    Client getrennt: 3876128
    Client getrennt: 3876096
    Client getrennt: 3876064
    Client getrennt: 3876032
    Client getrennt: 3876000
    Client getrennt: 3875968
    Client getrennt: 3875936
    Client getrennt: 3875904
    Client getrennt: 3875872
    Client getrennt: 3875840
    Client getrennt: 3875808
    Client getrennt: 3875776
    Client getrennt: 3875744
    Client getrennt: 3875712
    Client getrennt: 3875680
    Client getrennt: 3875648
    Client getrennt: 3875616
    Client getrennt: 3875584
    Client getrennt: 3875552
    Client getrennt: 3875520
    Client getrennt: 3875488
    Client getrennt: 3875456
    Client getrennt: 3875424
    Client getrennt: 3875392
    Client getrennt: 3875360
    Client getrennt: 3875328
    Client getrennt: 3875296
    Client getrennt: 3875264
    Client getrennt: 3875232
    Client getrennt: 3875200
    Client getrennt: 3875168
    Client getrennt: 3875136
    Client getrennt: 3875104
    Client getrennt: 3875072
    Client getrennt: 3875040
Zuletzt geändert von Toshy am 15.01.2007 02:51, insgesamt 5-mal geändert.
1. Win10
PB6.1
Benutzeravatar
mk-soft
Beiträge: 3853
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Sehe keine Verwaltung der angemeldeten Clients.

Case 1: Client anlegen mit der der ClientID. Vorher prüfen ob der Client vielleicht schon gibt und diesen erste löschen.

Case 4: Client wieder löschen.

Entweder über ein Array Struktur oder einer LinkedList die Client Verwalten.

Beispiel von mir:
http://www.purebasic.fr/german/viewtopi ... =varserver

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Darum geht es nicht. Über ob ein Client vielleicht schon existiert ist recht leicht, würde nur unnötig Rechenkapazität brauchen.Aber das löst das Problem nicht. Denn in dem Falle würde was noch schlimmeres passieren, dann würde verspätet ein Disconnect kommen von einer Verbindung die dann noch bzw. schon wieder existiert.

Wie gesagt, es ist quasie der Originalcode aus der Demo um es nachvollziehbar zu machen. Es geht also nur um das Problem, das sehr eigenartiger Weise die Disconnects nachrangig verarbeitet werden und nicht nach eingang. Das darf doch nicht sein. Das wäre ja ähnlich, als ob man bei einer LinkedList Datensätze anhängt, diese dann dann je nach Inhalt am Anfang oder am Ende der Liste zu finden sind, ohne das man aber entscheiden könnte was man abfragt.

Weshalb ist das so, ich vermutete ja einen Bug, hatte den Hinweis auf einen möglichen Bug erstmal aus dem Titel genommen, weil ich es erstmal klären wollte.
Ich hatte hier schon beim testen dutzende neue Verbindungen aufgebaut ohne das auch nur ein einziges Disconnect auftritt. Es hat ja nicht nur Nachteile in der Verwaltung (falls es doppelte Nummer gibt), sondern vor allem kann man dann Verloren gegangene Verbindungen nicht neu aufbauen usw.
Fakt ist, das so ein Verhalten extrem Nachteilig ist, unlogisch und wohl nicht sein dürfte.

Toshy
1. Win10
PB6.1
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Wie man an der Debugausgabe sieht und mir jetzt erst aufgefallen ist, werden die Disconnects wenn sie dann doch irgendwann mal bearbeitet werden auch noch in verkehrter Reihenfolge abgearbeitet, nicht das erste vorkommende Disconnect, sondern das letzte wird zu erst verarbeitet. Schrecklich.

Beim letzten Beitrag habe ich wohl etwas früh Andre gefragt, wohl war es schon wichtig, aber ich denke genügend geklärt, hoffe ich ;-)

Aber hier wäre es schön, wenn Andre doch mal Fred nachfragt was da los ist. Das ist sehr eigenartig.
Anliegen also kurz zusammen gefaßt:
1. Wenn der Server ausgelastet / langsam ist, dann werden die Disconnects er abgearbeitet NACHDEM ALLE Connect abgearbeitet wurden.
2. Sobald DANN die Disconnects abgearbeitet werden, werden erst die zu letzt aufgetreteten, nicht du zu erst / ältesten Disconnects abgearbeitet. Das kann doch nicht richtig sein.
* Es muß an PB liegen, da der REchner und die Verbindung nicht mal annähernd ausgelastet sind.

Gruß
Toshy
1. Win10
PB6.1
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Hallo!

In meinem Projekt, einem HTTP-Webserver, muss ich auch viele (tausende) Verbindungen entgegen nehmen, Daten empfangen+senden, dann die Verbindung wieder schließen.

Ich habe auch viel mit Threads gearbeitet: Der Hauptthread speichert von neuen CLienten die ConnectionID in einer globalen LinkedList und löscht bei Verbindungstrennung die ConnectionId aus der globalen LinkedList. Für jede ConnectionID wird ein separatoer Thread erstellt, der sich nur um den einen CLienten kümmert; trennt der CLient de Verbindung, wird auch der Thraed geschlossen.

Ich habe nicht alles gelesen, sorry.
Aber ich rate dir dringend, mal einen Blick auf die Mutex-Befehle zu schauen! Damit kannst du deine Threads und dein Hauptprogramm synchronisieren. Möglicherweise hilft auch das Einschalten der Threadsafe-Option in den Compilereinstellungen.
Diese beiden Dinge sind neu seit PB 4.0. :D
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Mutex nutze ich, hat aber nichts mit dem PRoblem zu tun. Auch kann und will ich nicht für jede Connection einen Thread verwenden, das ist gut, bei zu viellen gleichzeitigen verbindungen.
Das Problem bleibt ein Problem, weil da was falsch läuft. Es ist kein Problem 10 000e gleichzeitige Verbindungen mit Thread oder ohne zu verarbeiten, sondern das sobald viele Connections gleichzeitig aufgebaut oder abgebrochen werden diese nicht bzw. erst extrem spät und dann noch in falscher Reihenfolge vom SERVEr wieder gegeben werden. Das hat nichts mit meinem Code zu tun oder einem Mutex.
Es kann nur ein Thread gleichzeitig abfragen an den Server stellen, besser gesagt, ob ein Event da war und welches. Kommen gleichzeitig mehrere an und das vielleicht noch ständig, dann kommt es zu diesem Serverfehler. Ob das nun bei nur wenigen PRogrammiern / Programmen überhaupt vorkommt ist egal, ein "Fehler" sollte beseitigt werden.
Wenn windows das Disconnect mitbekommt, dann sollte es doch möglich sein, das auch PB das in der richtigen Reihenfolge abgibt an den USer. Es kann natürlich sein, das windowsinterne Listen auch so falsch rum arbeiten, ein Bug drinn ist, aber das kann halt wohl nur Fred sagen oder Andre. Könnte ich Englisch, würde ich ja Fred direkt fragen.

ich vermute, das Fred ausversehen die interne Liste für die Clientverwaltung, besser gesagt die Eventempfangsliste/-buffer falsch rum abfragt oder so.

Toshy
1. Win10
PB6.1
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Hmm, ich komme so nicht weiter, weil mein Programm ständig daten versuchen würde, obwohl die Verbindung beendet ist. Ne gute Programmstruktur sollte das verhindern, geht aber nicht, wenn ich das Disconnect so spät mitbekommen.
Hoffe das Andre mal an Fred in Kurz weiterleitet.

Kann den Code und das Verhalten (also die Debugausgabe) jemand nachvollziehen?

Ach ja, getestet unter WIndowsXP, SP2 glaube ich.
1. Win10
PB6.1
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Katastrophe !!!!

Bisher war es ja nur das verspätete Disconnect was große Probleme auslösen kann bzw. es tut, aber ich dachte, das kann man wenigstens umgehen, in dem man Serverseitig noch genauer darauf achtet ob die Daten gesendet wurden oder nicht und wenn nicht, noch ne überprüfung stattfindet bzw. einige Zeit gewartet wird ob die Verbindung noch besteht.
Aber das kann man vergessen.
Ich habe den Code mal um einige Debugausgaben erweitert, und man glaubt es nicht, obwohl der Client die Verbindungen bereits getrennt hat, bevor der Server überhaupt mitbekommt das diese geöffnet wurden, kann man nicht nur an den "schon wieder getrennten Cliente" vom Server aus Daten senden, sondern der Server von PB gibt sogar an, das diese korrekt versendet wurden. Das darf doch nicht war sein !!!!!????

Code: Alles auswählen

; ------------------------------------------------------------
;
;   PureBasic - Network (Server) example file
;
;    (c) 2003 - Fantaisie Software
;
; ------------------------------------------------------------
;

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf
Global go1.b
Procedure proc_ThreadFuerServerUeberwachung(plcebo)
  port = 6832
Buffer = AllocateMemory(1000)
If CreateNetworkServer(0, port)
  go1 = 1
   ; MessageRequester("PureBasic - Server", "Server created (Port "+Str(port)+").", 0)
    Repeat
     SEvent = NetworkServerEvent()
    If SEvent
      ClientID = EventClient()
      Select SEvent
        Case 1
          ;MessageRequester("PureBasic - Server", "A new client has connected !", 0)
          Debug "neuer Client: "+Str(ClientID)
          string.s = "0123456789"
          Debug "S send: " + Str( SendNetworkData(ClientID, @string, 10) )
          ;Debug "S disconnect: "+ Str( CloseNetworkConnection(ClientID) )
        Case 22
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a packet !", 0)
          ReceiveNetworkData(ClientID, Buffer, 1000)
          MessageRequester("Info", "String: "+PeekS(Buffer), 0)
        Case 3
          MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a file via the network !", 0)
          ReceiveNetworkFile(ClientID, "C:\TEST_Network.ftp3")
        Case 4
          ;MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connexion...", 0)
          ;Quit = 1
          Debug "Client getrennt: "+Str(ClientID)
      EndSelect
    EndIf
    Delay(100)
  Until Quit = 1 
   ;MessageRequester("PureBasic - Server", "Click to quit the server.", 0)
   CloseNetworkServer(0)
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf
EndProcedure
Debug "thread erstellen mit Sever"
CreateThread(@proc_ThreadFuerServerUeberwachung(), 0)
Debug "warte auf Server"
Repeat
  Delay(1)
Until go1 = 1
Debug "Verbindungen werden aufgebaut"

port = 6832

While a.l < 600*10
  a = a+1
  If a < 10
ConnectionID = OpenNetworkConnection("127.0.0.1", port)
If ConnectionID
  ;MessageRequester("PureBasic - Client", "Client connected to server...", 0)
  ;CloseNetworkConnection(ConnectionID)
  ;SendNetworkString(ConnectionID, "An hello from a client !!! :-)")
  
  ;MessageRequester("PureBasic - Client", "A string has been sent to the server, please check it before quit...", 0)
     string.s = "0123456789"
  Debug "C send: " + Str( SendNetworkData(ConnectionID, @string, 10) )
  Debug "disconnect: "+ Str( CloseNetworkConnection(ConnectionID) )
Else
  MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf
EndIf
Delay(10)
Wend


End   
Zuletzt geändert von Toshy am 07.01.2007 01:04, insgesamt 1-mal geändert.
1. Win10
PB6.1
Benutzeravatar
mk-soft
Beiträge: 3853
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Nach Beschreibung des TCP/IP kann nicht gewährleistet werden das die Pakete in der richtigen Reihenfolge ankommen.
Es kann durchaus sein das die Pakete über verschiedene Server und Router laufen und so mit auch unterschiedliche Laufzeiten sich ergeben.
Was aber das TCP/IP gewährleistet ist das das Paket, so wie der Verbindungsaufbau und Abbau Quittiert wird. Desweiteren überprüft das TCP auch ob das Paket ohne Fehler (CRC) übertragen wird und sendet das Paket bei einen Fehler noch mal. Dieses führt somit auch wieder zu verschiedenen Laufzeiten von Paketen.
Für die Abarbeitung der Pakete in der richtigen Reihenfolge ist somit der Programmieren verantwortlich.

Um eine stabile Abarbeitung zu erreichen ist es sinnvoll das der Server passiv arbeitet und nur auf Anforderung von den Client die Daten Sendet.

Bei einen nicht vorher gesehenen Abbruch der Verbindung kann es passieren das die Quittierung des Senden bis zu 30 Sekunden dauert, da versucht wird die Verbindung über die gesamte Welt wieder zu finden.

Somit finde ich die Idee auch gut mit vielen Thread zu arbeiten.

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> Nach Beschreibung des TCP/IP kann nicht gewährleistet werden das die Pakete in der richtigen Reihenfolge ankommen.
> Es kann durchaus sein das die Pakete über verschiedene Server und Router laufen und so mit auch unterschiedliche Laufzeiten sich ergeben. Für die Abarbeitung der Pakete in der richtigen Reihenfolge ist somit der Programmieren verantwortlich.

Zeig mir bitte mal die Stelle, wo das beschrieben wird, das würd ich gern mal sehen. Denn du hast AFAIK nicht recht. Das TCP Protokoll achtet sehr wohl auf die richtige Reihenfolge.
Ansonsten hast du Recht, bzgl. der Fehlerkorrektur.
Auszug aus Wikipedia, TCP/IP hat geschrieben:Im Gegensatz zum verbindungslosen UDP implementiert TCP einen bidirektionalen, byte-orientierten, zuverlässigen Datenstrom zwischen zwei Endpunkten. Das darunterliegende Protokoll (IP) ist paketorientiert, wobei Datenpakete verlorengehen können, in verkehrter Reihenfolge ankommen dürfen und sogar doppelt empfangen werden können. TCP wurde entwickelt, um mit der Unsicherheit der darunterliegenden Schichten umzugehen. Es prüft daher die Integrität der Daten mittels der Prüfsumme im Paketkopf und stellt die Reihenfolge durch Sequenznummern sicher. Der Sender wiederholt das Senden von Paketen, falls keine Bestätigung innerhalb einer bestimmten Zeitspanne (Timeout) eintrifft. Die Daten der Pakete werden beim Empfänger in einem Puffer in der richtigen Reihenfolge zu einem Datenstrom zusammengefügt und doppelte Pakete verworfen.
TCP achtet sehr wohl auf die richtige Reihenfolge, der Programmier muss nichts weiter tun.

Wer also bei Netzwerksachen auf Nummer sicher gehen will, sollte TCP statt UDP benutzen.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Gesperrt