Communication Client Serveur

Sujets variés concernant le développement en PureBasic
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Communication Client Serveur

Message par falsam »

Lorsque qu'on envoie des données à un serveur avec la commande SendNetworkString(), le buffer de réception peut soit contenir un seul SendNetworkString() ou plusieurs à la suite sans aucune séparation.

De-concaténer une telle chaîne n'est pas pratique.

J'ai quelques questions :
- Quelle serait la bonne taille du buffer de réception utilisé par la commande ReceiveNetworkData() ?
- J'ai des idées pour concaténer la chaîne envoyée par le client mais vous quelle méthode vous utilisez ?

Vous trouverez un exemple de serveur simplifié ainsi qu'un client simplifié envoyant plusieurs données au serveur avant de se déconnecter.

server.pb

Code : Tout sélectionner

If InitNetwork() = 0
  Debug  "Server - Can't initialize the network !"
  End
EndIf

Port = 6832
*Buffer = AllocateMemory(1000)

If CreateNetworkServer(0, Port)
  Debug "Server - Server created (Port "+Str(Port)+")."
  Repeat
    SEvent = NetworkServerEvent()
    
    If SEvent
      ClientID = EventClient()
      Select SEvent
          
        Case #PB_NetworkEvent_Connect
          Debug "Server - A new client has connected !"
          
        Case #PB_NetworkEvent_Data
          Debug "Server - Client "+Str(ClientID)+" has send a packet !"
          FreeMemory(*Buffer)
          *Buffer = AllocateMemory(1000)
          ReceiveNetworkData(ClientID, *Buffer, 1000)
          Debug "Server - *Buffer: "+PeekS(*Buffer, -1, #PB_UTF8)
          
        Case #PB_NetworkEvent_Disconnect
          Debug "Server - Client " + Str(ClientID)+" has closed the connection..."
          
      EndSelect
    EndIf
    
  ForEver 
  
  CloseNetworkServer(0)
Else
  Debug "Server - Can't create the server (port in use ?)."
EndIf
Client.pb

Code : Tout sélectionner

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6832
ConnectionID = OpenNetworkConnection("127.0.0.1", Port)

If ConnectionID
  Debug "Client - Connected To server..."
  
  Debug "Client - A string has been sent To the server ..."
  For i = 0 To 10
    SendNetworkString(ConnectionID, "Event 1 - " + i, #PB_UTF8)    
    SendNetworkString(ConnectionID, "Event 2 - " + i, #PB_UTF8)    
  Next    
  CloseNetworkConnection(ConnectionID)
Else
  Debug "Client -  Oops ! Can't find the server (Is it launched ?)."
EndIf
Regarder le résultat reçu par la commande dans la ligne ReceiveNetworkData(ClientID, *Buffer, 1000) du serveur.
Parfois il reçoit un seul évenement envoyé par le client et parfois il en reçoit plusieurs à la suite sans aucun caractère de séparation.
Debug a écrit :Server - A new client has connected !
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 0Event B - 0
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 1
Server - Client 37358352 has send a packet !
Server - *Buffer: Event B - 1
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 2
Server - Client 37358352 has send a packet !
Server - *Buffer: Event B - 2
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 3
Server - Client 37358352 has send a packet !
Server - *Buffer: Event B - 3
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 4
Server - Client 37358352 has send a packet !
Server - *Buffer: Event B - 4
Server - Client 37358352 has send a packet !
Server - *Buffer: Event A - 5
Server - Client 37358352 has send a packet !
Server - *Buffer: Event B - 5Event A - 6Event B - 6Event A - 7Event B - 7Event A - 8Event B - 8Event A - 9Event B - 9Event A - 10Event B - 10
Server - Client 37358352 has closed the connection...
Merci d'avance pour vos réponses.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Communication Client Serveur

Message par Zorro »

voila comment je ferai :

Serveur :

Code : Tout sélectionner

 If InitNetwork() = 0
      Debug  "Server - Can't initialize the network !"
      End
EndIf
Port = 6832
*Buffer = AllocateMemory(1000)
If CreateNetworkServer(0, Port)
      Debug "Server - Server created (Port "+Str(Port)+")."
      Repeat
            SEvent = NetworkServerEvent()
            If SEvent
                  ClientID = EventClient()
                  Select SEvent
                  Case #PB_NetworkEvent_Connect
                        Debug "Server - A new client has connected !"
                  Case #PB_NetworkEvent_Data                  
                        Debug "Server - Client "+Str(ClientID)+" has send a packet !"                     
                        *Buffer = AllocateMemory(1024)                      
                        ReceiveNetworkData(ClientID, *Buffer, 1024) ; reçois la taille du message
                        taille=Val(stringfield(PeekS(*Buffer,-1, #PB_UTF8),1,";"))
                        nbr_phrase=Val(stringfield(PeekS(*Buffer,-1, #PB_UTF8),2,";"))
                        
                        if Taille>0
                              *Buffer2 = AllocateMemory(taille)
                              ReceiveNetworkData(ClientID, *Buffer2,taille)
                              complete_message.s=PeekS(*Buffer, -1, #PB_UTF8)
                              Debug "Server - *Buffer: "+complete_message.s
                              For i=3 to nbr_phrase  ; on saute les 2 informations de debut qui indique la taille en caracteres d message , et le nombre de phrase
                                    debug stringfield(complete_message.s,i,";")                  
                              Next i
                        Endif
                  Case #PB_NetworkEvent_Disconnect
                        Debug "Server - Client " + Str(ClientID)+" has closed the connection..."
                  EndSelect
            EndIf
      ForEver
      CloseNetworkServer(0)
Else
      Debug "Server - Can't create the server (port in use ?)."
EndIf



Client :

Code : Tout sélectionner

 If InitNetwork() = 0
      MessageRequester("Error", "Can't initialize the network !", 0)
      End
EndIf
Port = 6832
ConnectionID = OpenNetworkConnection("127.0.0.1", Port)
If ConnectionID
      Debug "Client - Connected To server..."
      Debug "Client - A string has been sent To the server ..."
      restore start:
      For i = 1 To 9
            read.s p.s         
            phrase.s=phrase.s+p.s+";"      
            nrb_message=nrb_message+1
      Next   
      taille=len( phrase.s)
      SendNetworkString(ConnectionID, str(taille)+";"+str(nrb_message+2)+";"+phrase.s, #PB_UTF8)       
      CloseNetworkConnection(ConnectionID)
Else
      Debug "Client -  Oops ! Can't find the server (Is it launched ?)."
EndIf
DataSection
      start:
      data.s "il etait une bergere"
      data.s "et ri et ron"
      data.s "petit patapon"
      data.s "il etait une bergere"
      data.s "qui gardait ses moutons"
      data.s "ron-ron"
      data.s "qui gardait ses moutons"
      data.s " rhoooo ! la belle chanson "
      data.s "que voila !"
      data.s "-1"
      fin:
EndDataSection

en clair , limiter le nombre de send-recept String au minimum
et ajouter des indications dans le message (ici taille du message pour le buffer , et nombre de phrases a afficher )
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Communication Client Serveur

Message par falsam »

Merci Zorro. J'ai testé ton code mais il ne me convient pas car si dans le cadre d'un chat par exemple, un utilisateur utilise le ";" alors ton systeme ne fonctionne pas. Bien sur je pourrais remplacer ce caractère par un autre mais je pense que le risque est le même.

Je pense que je vais passer une chaine JSON entre le client et le serveur.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Communication Client Serveur

Message par Zorro »

si dans le cadre d'un chat par exemple, un utilisateur utilise le ";" alors ton systeme ne fonctionne pas. Bien sur je pourrais remplacer ce caractère par un autre mais je pense que le risque est le même.
pas vraiment, n'oublie pas qu'on est en unicode
parmis les nombreux caracteres de l'unicode, il y en a bien un qui peut servir de separateur ...

tu peux aussi mettre un "agent de surveillance" , qui guette , un petit filtre sur les caracteres autorisé , et voila
genre, tu autorises les codes 32 a 127 , et tu prends un caracteres >127 pour faire le separateur
l'imagination au pouvoir :)
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Communication Client Serveur

Message par falsam »

Un serveur et un client communiquant avec une structure exporter/importer via JSON

Structure commune au serveur et au client

Code : Tout sélectionner

Structure NewMessage
  event.s
  message.s
EndStructure
-La variable event.s contient un événement.
-La variable message.s contient le message associé.
Exemple :
"Event_MovetoXY" : Un sprite se déplace - Message contiendra la position x et y du sprite.
"Event_UserMessage" : Un utilisateur laisse un message - Message contiendra le message utilisateur.

Server.pb

Code : Tout sélectionner

;Structure Message
Structure NewMessage
  event.s
  message.s
EndStructure
Global NewList Messages.NewMessage(), Buffer.s, Messages.s 


If InitNetwork() = 0
  Debug  "Server - Can't initialize the network !"
  End
EndIf

Port = 6832
*Buffer = AllocateMemory(5120)

If CreateNetworkServer(0, Port)
  Debug "Server - Server created (Port "+Str(Port)+")."
  Repeat
    SEvent = NetworkServerEvent()
    
    If SEvent
      ClientID = EventClient()
      Select SEvent
          
        Case #PB_NetworkEvent_Connect
          Debug "Server - A new client has connected !"
          
        Case #PB_NetworkEvent_Data
          Debug "Server - Client "+Str(ClientID)+" has send a packet !"
          FreeMemory(*Buffer)
          *Buffer = AllocateMemory(5120)
          
          ;Receiving the message
          ReceiveNetworkData(ClientID, *Buffer, 5120)
          Buffer = PeekS(*Buffer, -1, #PB_UTF8) 
          
          ;JSON formatting
          Messages = "[" + LSet(Buffer, Len(Buffer)-1) + "]" 
          
          ;Send the JSON string to the linked list messages()
          If ParseJSON(0, Messages)
            ExtractJSONList(JSONValue(0), Messages())
            ForEach Messages()
              Debug Messages()\event + " " + Messages()\message 
            Next
          Else
            Debug "Serveur - Error JSON "  + JSONErrorMessage() + " " + JSONErrorPosition() 
          EndIf
          
        Case #PB_NetworkEvent_Disconnect
          Debug "Server - Client " + Str(ClientID)+" has closed the connection..."
          
      EndSelect
    EndIf
    
  ForEver 
  
  CloseNetworkServer(0)
Else
  Debug "Server - Can't create the server (port in use ?)."
EndIf
Client.pb

Code : Tout sélectionner

Structure NewMessage
  event.s
  message.s
EndStructure
Global Message.NewMessage

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6832
ConnectionID = OpenNetworkConnection("127.0.0.1", Port)

If ConnectionID
  Debug "Client - Connected To server..."
  
  ;Send 100 messages
  Debug "Client - A string has been sent To the server ..."
  For i = 0 To 99
    With Message
      \event    = "Event" + i 
      \message  = "Message" + i 
      
      ;JSON formatting
      If CreateJSON(0)
        InsertJSONStructure(JSONValue(0), @Message, NewMessage)
        SendNetworkString(ConnectionID, ComposeJSON(0) + ",")  
      EndIf  
    EndWith
  Next    
  CloseNetworkConnection(ConnectionID)
Else
  Debug "Client -  Oops ! Can't find the server (Is it launched ?)."
EndIf
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Communication Client Serveur

Message par falsam »

Jusqu'à présent la communication fonctionnait que dans le sens Client -> Serveur.

Avec les codes qui suivent, le client va emettre 100 messages vers le serveur comme dans le code précédent mais aussi recevoir le message de bienvenu du serveur.

Client.pb

Code : Tout sélectionner

Structure NewMessage
  event.s
  message.s
EndStructure

;Send message
Global Message.NewMessage

;Receive message(s)
Global NewList Messages.NewMessage(), Buffer.s, Messages.s 

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

*Buffer = AllocateMemory(5120)
Port = 6832
ConnectionID = OpenNetworkConnection("127.0.0.1", Port)

If ConnectionID  
  Debug "Client - Connected To server..."
  
  ;Send 100 messages
  Debug "Client - A string has been sent To the server ..."
  For i = 0 To 99
    With Message
      \event    = "Event" + i 
      \message  = "Message" + i 
      
      ;JSON formatting
      If CreateJSON(0)
        InsertJSONStructure(JSONValue(0), @Message, NewMessage)
        SendNetworkString(ConnectionID, ComposeJSON(0) + ",")  
      EndIf  
    EndWith
  Next    
  
  Repeat
    Connection = NetworkClientEvent(ConnectionID)
    If Connection
      Select Connection              
        Case #PB_NetworkEvent_Data
          Debug "Client - Server has send a packet !"
          FreeMemory(*Buffer)
          *Buffer = AllocateMemory(5120)
          
          ;Receiving the message
          ReceiveNetworkData(ConnectionID, *Buffer, 5120)
          Buffer = PeekS(*Buffer, -1, #PB_UTF8)
          
          ;JSON formatting
          Messages = "[" + LSet(Buffer, Len(Buffer)-1) + "]" 
          
          ;Send the JSON string to the linked list messages()
          If ParseJSON(0, Messages)
            ExtractJSONList(JSONValue(0), Messages())
            ForEach Messages()
              Debug Messages()\event + " " + Messages()\message 
            Next
          Else
            Debug "Serveur - Error JSON "  + JSONErrorMessage() + " " + JSONErrorPosition() 
          EndIf
      EndSelect
    EndIf
  ForEver 
  
  CloseNetworkConnection(ConnectionID)
Else
  Debug "Client -  Oops ! Can't find the server (Is it launched ?)."
EndIf
Server.pb

Code : Tout sélectionner

;Structure Message
Structure NewMessage
  event.s
  message.s
EndStructure

;Send message
Global Message.NewMessage

;Receive message(s)
Global NewList Messages.NewMessage(), Buffer.s, Messages.s 


If InitNetwork() = 0
  Debug  "Server - Can't initialize the network !"
  End
EndIf

Port = 6832
*Buffer = AllocateMemory(5120)

If CreateNetworkServer(0, Port)
  Debug "Server - Server created (Port "+Str(Port)+")."
  Repeat
    SEvent = NetworkServerEvent()
    
    If SEvent
      ClientID = EventClient()
      Select SEvent
          
        Case #PB_NetworkEvent_Connect
          Debug "Server - A new client has connected !"
          
          ;Send welcome message
          With Message
            \event    = "Event_ServerMessage" 
            \message  = "Hello"
            
            ;JSON formatting
            If CreateJSON(0)
              InsertJSONStructure(JSONValue(0), @Message, NewMessage)
              SendNetworkString(ClientID, ComposeJSON(0) + ",")  
            EndIf  
          EndWith
          
        Case #PB_NetworkEvent_Data
          Debug "Server - Client "+Str(ClientID)+" has send a packet !"
          FreeMemory(*Buffer)
          *Buffer = AllocateMemory(5120)
          
          ;Receiving the message
          ReceiveNetworkData(ClientID, *Buffer, 5120)
          Buffer = PeekS(*Buffer, -1, #PB_UTF8) 
          
          ;JSON formatting
          Messages = "[" + LSet(Buffer, Len(Buffer)-1) + "]" 
          
          ;Send the JSON string to the linked list messages()
          If ParseJSON(0, Messages)
            ExtractJSONList(JSONValue(0), Messages())
            ForEach Messages()
              Debug Messages()\event + " " + Messages()\message 
            Next
          Else
            Debug "Serveur - Error JSON "  + JSONErrorMessage() + " " + JSONErrorPosition() 
          EndIf
          
        Case #PB_NetworkEvent_Disconnect
          Debug "Server - Client " + Str(ClientID)+" has closed the connection..."
          
      EndSelect
    EndIf
    
  ForEver 
  
  CloseNetworkServer(0)
Else
  Debug "Server - Can't create the server (port in use ?)."
EndIf
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Communication Client Serveur

Message par djes »

Pour info, j'avais fait un code client/serveur il y a longtemps. J'avais fait un truc de ce genre :

Code : Tout sélectionner

				SEvent = NetworkServerEvent()
			
				If SEvent
					ClientID.l = NetworkClientID()

					Select SEvent

					;New client
					Case 1
			
					;A client is leaving
					Case 4
						CloseNetworkConnection(ClientID)
			
					;Raw data has been received
					Case 2
						done.l = #False																;if done then close socket, either gracefull or due to an error
						Repeat
							ClearBuffer()
							RequestLength = ReceiveNetworkData(ClientID, *buffer, 4096)
							If RequestLength > 0
								TraiteRequete()
							ElseIf RequestLength = 0
								Done = #True
							Else
								Error = WSAGetLastError_()			
								If Error = #WSAEWOULDBLOCK									;we are non-blocking so: no more data to read
									Delay(100)
									Done = #True														;so close the socket
								ElseIf Error <> 0
									Done = #True 
								EndIf			
							EndIf
						Until Done = #True
					
					EndSelect

				EndIf
Edit : Ah, oui, mais j'utilisais le mode asynchrone, avec

Code : Tout sélectionner

     #FD_ALL = #FD_OOB|#FD_ACCEPT|#FD_CONNECT|#FD_CLOSE
     WSAAsyncSelect_(socket, WindowID(0), #WM_NULL, #FD_ALL)
Je ne sais pas si c'est encore utile...
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Communication Client Serveur

Message par falsam »

Merci djes de te pencher sur ce sujet.
djes a écrit :Je ne sais pas si c'est encore utile...
Hum hum je ne sais pas si ça répond à la question relative à la concaténation des messages qui me préoccupe actuellement ^^

La solution JSON me plait bien. Je vais tacher de mettre en place une toute petite démo Tchat + 2D moins barbante que cette étalages de codes que j'ai pu produire.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Communication Client Serveur

Message par djes »

falsam a écrit :Merci djes de te pencher sur ce sujet.
djes a écrit :Je ne sais pas si c'est encore utile...
Hum hum je ne sais pas si ça répond à la question relative à la concaténation des messages qui me préoccupe actuellement ^^

La solution JSON me plait bien. Je vais tacher de mettre en place une toute petite démo Tchat + 2D moins barbante que cette étalages de codes que j'ai pu produire.
Oui, pour la concaténation, tu as raison, mais je pense que tu as vu pourquoi j'ai posté ça ;)
Pour JSON pourquoi pas ; en tous cas, je ne trouve pas que tes démos soient barbantes.
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Communication Client Serveur

Message par Zorro »

djes a écrit :Pour JSON pourquoi pas ; en tous cas, je ne trouve pas que tes démos soient barbantes.
tain..... laisse le, pour une fois qu'il a un éclair de lucidité :mrgreen:


Arf ... Sorry c'etait vraiment trop tentant :lol:
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Communication Client Serveur

Message par Kwai chang caine »

J'ai une question qui me taraude depuis un bon moment, et puisque vous parlez de client/serveur :wink:
Mon geek m'avait parlé d'un truc que je croyais pas possible, mais je me rappelle plus le nom :oops:
Une histoire de client/serveur qui se connectaient en "dual je sais pas quoi" ou "half" ou un truc comme ça, qui permettait de se connecter entre eux bien plus facilement que comme on fait nous avec client/serveur, sans rentrer d'IP....
J'ai rêvé ??? :oops:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Communication Client Serveur

Message par falsam »

falsam a écrit :je pense que tu as vu pourquoi j'ai posté ça
Rhaaa je déteste. Ca doit être tellement évident que je ne vois pas.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Communication Client Serveur

Message par djes »

falsam a écrit :
falsam a écrit :je pense que tu as vu pourquoi j'ai posté ça
Rhaaa je déteste. Ca doit être tellement évident que je ne vois pas.
Sans aucun doute ! En plus il y a deux trucs au moins !
Répondre