Aktuelle Zeit: 19.06.2018 00:54

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 40 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3, 4
Autor Nachricht
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 27.02.2018 17:25 
Offline

Registriert: 19.10.2014 15:51
Leider hängt sich der Server immer wieder auf und reagiert nicht mehr, sobald mehrere Client dran sind.
Ich gehe mal stark davon aus, dass das an den Threads liegt.

Nun brauche ich keinen Server, der hunderte Clients managen kann und da ich das mit den Threads und dem Mutex im Leben nicht verstehe, würde ich mich sehr freuen, wenn mir jemand zeigen kann, wie ich den Servercode ohne Threads bekomme.

_________________
Ich programmiere plattformunabhängig und suche immer Lösungen für alle Plattformen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 28.02.2018 10:18 
Offline
Benutzeravatar

Registriert: 08.09.2004 08:53
Da fehlte glaub ich im Event Handling ein Mutex..

_________________
"Papa, ich laufe schneller, dann ist es nicht so weit."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 28.02.2018 15:29 
Offline
Benutzeravatar

Registriert: 24.02.2007 22:15
stevie1401 hat geschrieben:
Leider hängt sich der Server immer wieder auf und reagiert nicht mehr, sobald mehrere Client dran sind.
Ich gehe mal stark davon aus, dass das an den Threads liegt.

Ich hab den Server gerade mit über 100 Verbindungen getestet, das ging so weit ohne Probleme (Unter Windows). Aber ich glaube einen Fall gefunden zu haben, der unter Linux zu einem Deadlock führt.
Deswegen bin ich gerade dabei eine VM aufzusetzen, um das Ganze zu testen. Falls du also Linux/MacOS verwendest, dann stehen die Chancen gut, dass ich gleich eine neue Version mit dem Bugfix hochlade.

_________________
Webseite


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 28.02.2018 16:46 
Offline

Registriert: 19.10.2014 15:51
@Dadido3, ich habe es mit Linux und Windows in allen Variationen getestet. Der Fehler war immer der gleiche.



Einige Erklärungen was ich gemachte habe im Code unter Case "Message"
Sollte es programmtechnisch FALSCH sein was ich gemacht habe, wäre über jede Hilfe Dankbar.

Noch einmal zur Erklärung.
Ich lasse über diesen Code einen Doppelkopf-Server laufen.
Alles was mit Doppelkopf zu tun hat, Spieler, Karten, alles, managet die Procedure Checknachricht.
Insofern ist es egal, ob dieser Server für einen Chat gemacht ist.
Relevant ist, dass Daten zuverlässeig vom Client zum Server und zurück kommen.
Ich kann manchmal mit 30 Spielern 1 Std spielen, aber die Regel ist, dass der Server nach wenigen Minuten einfach nicht mehr erreichbar ist und einfach nichts mehr macht.
In einer Leelaufschleife scheint er nicht zu sein, denn die CPU-Last ist bei rund 0-1 %


Code:

Procedure WebSocket_Event(*Server, *Client, Event, *Event_Frame.WebSocket_Server::Event_Frame)
  Protected Chat_Message.Chat_Message
  Protected Chat_Username_Change.Chat_Username_Change
  Protected Chat_Userlist.Chat_Userlist
  Protected JSON_ID.i
  Protected JSON2_ID.i
 
  LockMutex(Mutex)
 
  Select Event
    Case WebSocket_Server::#Event_Connect
      PrintN(" #### Client connected: " + *Client)
      AddElement(Client())
      Client()\WebSocket_Client = *Client
     
      JSON2_ID = CreateJSON(#PB_Any)
      If JSON2_ID
       
        Chat_Userlist\Type = "Userlist"
        ForEach Client()
          AddElement(Chat_Userlist\UserName())
          Chat_Userlist\UserName() = Client()\Username
        Next
       
        InsertJSONStructure(JSONValue(JSON2_ID), Chat_Userlist, Chat_Userlist)
       
        WebSocket_Server::Frame_Text_Send(*Server, *Client, ComposeJSON(JSON2_ID))
       
        FreeJSON(JSON2_ID)
      EndIf
     
    Case WebSocket_Server::#Event_Disconnect
      PrintN(" #### Client disconnected: " + *Client)
      ForEach Client()
        If Client()\WebSocket_Client = *Client
          DeleteElement(Client())
          Break
        EndIf
      Next
     
      JSON2_ID = CreateJSON(#PB_Any)
      If JSON2_ID
       
        Chat_Userlist\Type = "Userlist"
        ForEach Client()
          AddElement(Chat_Userlist\UserName())
          Chat_Userlist\UserName() = Client()\Username
        Next
       
        InsertJSONStructure(JSONValue(JSON2_ID), Chat_Userlist, Chat_Userlist)
       
        ForEach Client()
          WebSocket_Server::Frame_Text_Send(*Server, Client()\WebSocket_Client, ComposeJSON(JSON2_ID))
        Next
       
        FreeJSON(JSON2_ID)
      EndIf
     
    Case WebSocket_Server::#Event_Frame
      Select *Event_Frame\Opcode
        Case WebSocket_Server::#Opcode_Ping
          PrintN(" #### Ping from *Client " + *Client)
        Case WebSocket_Server::#Opcode_Text
          JSON_ID = CatchJSON(#PB_Any, *Event_Frame\Payload, *Event_Frame\Payload_Size)
          If JSON_ID
           
            Select GetJSONString(GetJSONMember(JSONValue(JSON_ID), "Type"))
              Case "Message"
                ExtractJSONStructure(JSONValue(JSON_ID), Chat_Message, Chat_Message)
                PrintN(Chat_Message\Author + ": " + Chat_Message\Message)
               
                Debug PeekS(*Event_Frame\Payload, *Event_Frame\Payload_Size, #PB_UTF8)
               
                ;Ich kann verste das mit dem JSON nicht, deshalb nenutze ich es nicht
                ;Relevant ist mich mich "Chat_Message"
               
               
                ;Hier baue ich meine eigene Procedure ein:
                ;In dieser Procedure wird alles geregelt, was ich benötige
               
                CheckNachricht(*client,Chat_Message)
                ;Aus "Checknachricht() heraus sende ich auch an die einzelnen Clients.
                ;Da die Procedure WebSocket_Event() am anfang ein  LockMutex(Mutex) benutzt,
                ;gehe ich davon aus, dass alles was ich innerhalb Checknachricht mache auch geschützt ist.
                ;Ich benutze innerhalb Checknachricht() KEIN  LockMutex(Mutex) -  UnLockMutex(Mutex)
               
               
               
              Case "Username_Change"
                ExtractJSONStructure(JSONValue(JSON_ID), Chat_Username_Change, Chat_Username_Change)
                ForEach Client()
                  If Client()\WebSocket_Client = *Client
                    Client()\Username = Chat_Username_Change\Username
                    Break
                  EndIf
                Next
               
                JSON2_ID = CreateJSON(#PB_Any)
                If JSON2_ID
                 
                  Chat_Userlist\Type = "Userlist"
                  ForEach Client()
                    AddElement(Chat_Userlist\UserName())
                    Chat_Userlist\UserName() = Client()\Username
                  Next
                 
                  InsertJSONStructure(JSONValue(JSON2_ID), Chat_Userlist, Chat_Userlist)
                 
                  ForEach Client()
                    WebSocket_Server::Frame_Text_Send(*Server, Client()\WebSocket_Client, ComposeJSON(JSON2_ID))
                  Next
                 
                  FreeJSON(JSON2_ID)
                EndIf
               
            EndSelect
           
            FreeJSON(JSON_ID)
          EndIf
      EndSelect
     
  EndSelect
 
  UnlockMutex(Mutex)
EndProcedure







Edith:
Ich benutze testweise gerade diesen Code:




Code:


Procedure WebSocket_Server(*Server.ServerStructure)
 
  Protected.i SEvent, ClientID, handshake, i, ClientIP, GadgetItem, ReceivedBytes
  Protected *Buffer
  Protected Header$, Key$, Accept$, Body$
 
  Protected Byte.a
  Protected.i Fin, Opcode, Masked, Payload, Ptr, n, Pos1, Pos2
  Protected Dim MaskKey.a(3)
 
 
 
  Protected j,k
  Protected.s   s
 
 
 
 
 Debug "Server"
 
  *Buffer = AllocateMemory(10240)
  If *Buffer
   
    Repeat
     
      SEvent = NetworkServerEvent()
      If SEvent
        ClientID = EventClient()
        ClientIP = GetClientIP(ClientID)
        Select SEvent
         
          Case #PB_NetworkEvent_Connect
            AddMapElement(*Server\Client(), Str(ClientID))
            ;StatusBarText(0, 1, "Clients: " + Str(MapSize(*Server\Client())), #PB_StatusBar_Center)
            ;DisableGadget(#TransmitButton, #False)
            ;DisableGadget(#DisconnectButton, #False)
            ;AddGadgetItem(#TransmitCombo, -1, Str(ClientID))
            ;AddGadgetItem(#TransmitCombo, -1, IPString(ClientIP) + " - " + Str(ClientID))
            ;GadgetItem = CountGadgetItems(#TransmitCombo) - 1
            ;SetGadgetItemData(#TransmitCombo, GadgetItem, ClientID)
            ;SetGadgetState(#TransmitCombo, GadgetItem)
            Debug "A new client has connected !"
           
          Case #PB_NetworkEvent_Data
            FillMemory(*Buffer, 10000)
            ReceivedBytes = ReceiveNetworkData(ClientID, *Buffer, 1000)
            Debug "Recv: " + Str(ReceivedBytes)
           
            If Not *Server\Client(Str(ClientID))\Handshake
             
              Header$ = PeekS(*Buffer, ReceivedBytes, #PB_UTF8)
             
              Pos1 = FindString(Header$, "Sec-WebSocket-Key: ")
              If Pos1
                Pos1 + 19
                Pos2 = FindString(Header$, #CRLF$, Pos1)
                If Pos2
                  Key$ = Trim(Mid(Header$, Pos1, Pos2 - Pos1))
                  Accept$ = SecWebsocketAccept(Key$)
                EndIf
              EndIf
              Header$ = "HTTP/1.1 101 Switching Protocols" + #CRLF$
              Header$ + "Upgrade: WebSocket"+ #CRLF$
              Header$ + "Connection: Upgrade"+ #CRLF$
              Header$ + "Sec-WebSocket-Accept: " + Accept$ + #CRLF$
              Header$ + #CRLF$
              SendNetworkString(ClientID, Header$)
              *Server\Client(Str(ClientID))\Handshake = #True
             
            Else
             
              Ptr = 0
              Byte = PeekA(*Buffer + Ptr)
              If Byte & %10000000
                Fin = #True
              Else
                Fin = #False
              EndIf
              Opcode = Byte & %00001111
              Ptr = 1
             
              Debug "Fin:" + Str(Fin)
              Debug "Opcode: " + Str(Opcode)           
             
             
              Byte = PeekA(*Buffer + Ptr)
              Masked = Byte >> 7
              Payload = Byte & $7F           
              Ptr + 1
             
              If Payload = 126
                Payload = PeekA(*Buffer + Ptr) << 8
                Ptr + 1
                Payload | PeekA(*Buffer + Ptr)
                Ptr + 1
              ElseIf Payload = 127
                Payload = 0
                n = 7
                For i = Ptr To Ptr + 7
                  Payload | PeekA(*Buffer + i) << (8 * n)
                  n - 1
                Next i
                Ptr + 8
              EndIf
             
              Debug "Masked: " + Str(Masked)
              Debug "Payload: " + Str(Payload)
             
              If Masked
                n = 0
                For i = Ptr To Ptr + 3
                  MaskKey(n) = PeekA(*Buffer + i)
                  Debug "MaskKey " + Str(n + 1) + ": " + RSet(Hex(MaskKey(n)), 2, "0")
                  n + 1
                Next i
                Ptr + 4
              EndIf
             
              Select Opcode
                Case #TextFrame
                  If Masked
                    n = 0
                    For i = Ptr To Ptr + Payload - 1
                      PokeA(*Buffer + i, PeekA(*Buffer + i) ! MaskKey(n % 4))
                      n + 1
                    Next i
                  EndIf
                 
                  Body$ = PeekS(*Buffer + Ptr, Payload, #PB_UTF8)
                 
                  ;AddGadgetItem(#ReceiveEdit, -1, IPString(ClientIP) + "-" + Str(ClientID) + ": " + Body$)
                  Debug "Text vom client: "+body$
                  checknachricht(ClientID,Body$)
                 
                Case #ConnectionCloseFrame
                  WebSocket_ClientDisconnect(ClientID, *Server)
                 
                Case #PingFrame
                  Byte = PeekA(*Buffer) & %11110000
                  PokeA(*Buffer, Byte | #PongFrame)
                  SendNetworkData(ClientID, *Buffer, ReceivedBytes)
                 
                Default
                  Debug "Opcode not implemented yet!"
              EndSelect
            EndIf
           
          Case #PB_NetworkEvent_Disconnect
            WebSocket_ClientDisconnect(ClientID, *Server)
           
        EndSelect
       
      Else
        Delay(10)
      EndIf
     
    ForEver
   
    FreeMemory(*Buffer)
   
  EndIf
 
EndProcedure







Ich habe diesen Code ohne Thread hinbekommen.
Funktioniert tadellos, zumindest ohne Abstürze oder Hänger - allerdings kommen nicht immer alle Nachrichten an.
Das war im ersten Code erheblich besser.

__________________________________________________
Quote-Tags>Code-Tags
28.02.2018
RSBasic

_________________
Ich programmiere plattformunabhängig und suche immer Lösungen für alle Plattformen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 28.02.2018 21:01 
Offline
Benutzeravatar

Registriert: 24.02.2007 22:15
Ich habe es nun unter Ubuntu getestet, aber ich konnte den Fehler auch dort nicht reproduzieren. Nichtsdestotrotz hab ich einen möglichen Deadlock behoben, und in der README beschrieben wie man die Events über polling abfragen kann. (Intern werden immernoch threads verwendet, aber das hat einen dann nicht mehr zu interessieren)

stevie1401 hat geschrieben:
Code:
;Da die Procedure WebSocket_Event() am anfang ein  LockMutex(Mutex) benutzt,
;gehe ich davon aus, dass alles was ich innerhalb Checknachricht mache auch geschützt ist.
;Ich benutze innerhalb Checknachricht() KEIN  LockMutex(Mutex) -  UnLockMutex(Mutex)

Der Mutex ist auch innerhalb deiner Funktion aktiv, er hat aber keine Bedeutung, wenn du in deinem Hauptprogramm, ohne diesen Mutex zu benutzen, auf irgendwelche Ressourcen/Listen/Speicher zugreifst, welche du auch in Checknachricht() benutzt.

Am Besten ist es du benutzt die Polling-Methode, so wird alles nacheinander abgearbeitet.
Desweiteren wäre es wahrscheinlich besser über Probleme mit dem Include und dessen Benutzung im jeweiligen Thread zu schreiben.

_________________
Webseite


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 28.02.2018 23:44 
Offline

Registriert: 19.10.2014 15:51
Erst einmal vielen Dank für deine fleissige Arbeit.
In deinem Example Chat Server Polling kann ich leider nicht erkennen was Polling ist, ob das ein Befehl, eine Procedure oder was auch immer ist. Das Wort Polling kommt in dem Beispiel nicht vor.
Die README ist leider nicht lesbar.

Vielleicht ginbt es ja eine einfache Antwort.
Wie kann ich die Procedure "checknachricht" schützen, dass ich in dieser auf globale Variablen zugreifen kann ohne dass es zu Abstürzen kommt?

_________________
Ich programmiere plattformunabhängig und suche immer Lösungen für alle Plattformen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 01.03.2018 00:40 
Offline
Benutzeravatar

Registriert: 24.02.2007 22:15
Du benutzt das Polling indem du
Code:
*Server = WebSocket_Server::Create(8090, @WebSocket_Event())
zu
Code:
*Server = WebSocket_Server::Create(8090)
abänderst.

Und dann in deine Hauptschleife
Code:
While WebSocket_Server::Event_Callback(*Server, @WebSocket_Event())
Wend
einfügst.

Dadurch wird dein Event-Handler nicht mehr von einem Thread, sondern von deinem Hauptprogramm aufgerufen. Du brauchst dann auch nichts weiter zu schützen.

_________________
Webseite


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 01.03.2018 01:22 
Offline

Registriert: 19.10.2014 15:51
Vielen herzlichen Dank!
habs auch gleich getestet.
Die 20 Dummyspieler konnten problemlos spielen.

Wenn allerdings 2 oder 3 Spieler fast gleichzeitig den Server disconnecten, kommt folgende Meldung:


[22:53:20] Executable-Typ: Windows - x64 (64bit, Unicode, Thread)
[22:53:20] Executable gestartet.
[23:17:31] [ERROR] WebSocket_Server.pbi (Zeile: 814)
[23:17:31] [ERROR] Das angegebene 'ConnectionID' ist null.

_________________
Ich programmiere plattformunabhängig und suche immer Lösungen für alle Plattformen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 01.03.2018 02:18 
Offline
Benutzeravatar

Registriert: 24.02.2007 22:15
Habe den Fehler behoben. Jetzt müsste eigentlich alles laufen.

_________________
Webseite


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: WebSocket Chatclient
BeitragVerfasst: 01.03.2018 09:49 
Offline

Registriert: 19.10.2014 15:51
Läuft jetzt per-fekt!
Du bist TOP! :allright:

Vielen, vielen Dank für deine Hilfe :)

_________________
Ich programmiere plattformunabhängig und suche immer Lösungen für alle Plattformen.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 40 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3, 4

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye