Demande de conseil pour mise en place client/serveur tcp

Sujets variés concernant le développement en PureBasic
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Bonjour,

Je souhaiterais créer un binôme client/serveur en TCP. Sachant que je pourrais avoir simultanément 1200 clients connectés (au maximum) sur un LAN, quels sont les points auxquels je dois faire attention ? Par exemple, j'ai lu sur le forum que certains créent une thread par connexion.
La partie serveur afficherait la liste des client connectés et permettrait des envois de commandes aux clients sélectionnés.
La partie cliente ferait remonter au serveur des infos techniques et donc exécuterait aussi les commandes reçues du serveur.
Quelle est la meilleure approche ?

En vous remerciant par avance.
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

Bonjour tatanas,

1200 clients et un serveur, ce n'est plus un binôme :P

Je ne pense pas que créer un thread par connexion soit une bonne idée (ni même faisable étant donné qu'il est possible que chaque thread se réserve un espace mémoire). (pas testé)

S'il s'agit comme pour l'un de tes projet de la gestions de périphériques par SNMP, je pense que le mieux est de faire du pooling SNMP dans le sens application vers les clients et d'utiliser les traps SNMP dans le sens client vers serveur (si les clients ont ce dispositif: les imprimantes réseau l'ont par exemple souvent)

:wink:
Avatar de l’utilisateur
Mindphazer
Messages : 635
Inscription : mer. 24/août/2005 10:42

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Mindphazer »

Tu peux aussi jeter un oeil ici : https://www.purebasic.fr/english/viewto ... 536083355b

(je ne sais absolument pas si ça peut répondre à ta demande !!)
Bureau : Win10 64bits
Maison : Macbook Pro M1 14" SSD 512 Go / Ram 16 Go - iPad Pro 32 Go (pour madame) - iPhone 15 Pro Max 256 Go
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Ce n'est pas un projet lié au snmp. Juste un moyen de récupérer des infos de postes clients sous Windows et leur transmettre des commandes à exécuter en local.
Donc clairement les requêtes partiraient des clients pour "alimenter" le serveur et parfois le serveur enverrait des ordres aux clients.

Lien intéressant pour des envois de données TCP supérieurs à 65536 octets ce qui semble être la limite des fonctions Purebasic.

Petite question liée à ce sujet : Comment doit on gérer la réception de données lorsque celles-ci sont incomplètes ? J'ai regardé quelques exemples de codes sur le forum mais les gens n'ont pas l'air de s'en soucier. Est-ce que ce genre de traitement convient ?

Code : Tout sélectionner

; réception de données envoyées par un SendNetworkString() en UTF8

DataReceived = ReceiveNetworkData(connectionID, *BufferReceive, BufferLen)
While DataReceived = BufferLen
	resultat = resultat + PeekS(*BufferReceive, -1, #PB_UTF8)
	DataReceived = ReceiveNetworkData(connectionID, *BufferReceive, BufferLen)
Wend

; traitement de resultat
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

Juste un moyen de récupérer des infos de postes clients sous Windows et leur transmettre des commandes à exécuter en local.
Tu ne veux pas utiliser les webservices (HTTPRequest()) ? cela serait bien plus simple et rapide à mettre en œuvre et à modifier. Tu peux écrire la partie serveur en PB ou utiliser un simple serveur web et un langage dynamique ou CGI.
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Disons que ça permettrait aux clients d'envoyer facilement les infos au serveur (web) mais le serveur ne pourrait envoyer ses ordres aux clients que si ces derniers hébergent aussi un serveur web, non ?
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

tatanas a écrit :Disons que ça permettrait aux clients d'envoyer facilement les infos au serveur (web) mais le serveur ne pourrait envoyer ses ordres aux clients que si ces derniers hébergent aussi un serveur web, non ?
Le principe du webservice c'est une question/réponse.
Le client envoie la question par GET ou POST (dans l'URL ou dans le corps)
Le serveur répond par une page unique formatée (texte, html, json, xml)
À partir de là, il suffit que le client analyse le contenu de la réponse et exécute l'ordre reçu.

La seule différence par rapport au web normal c'est qu'on n'utilise pas de navigateur. C'est au client (programme) de voir ce qu'il veut faire avec le fichier reçu. Donc ici, par exemple tu utilises un FindString() pour lire une commande dans le texte que tu utilises ensuite dans RunProgram()

:wink:
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Je comprends bien. Mais le client ne sait pas à priori quand il va recevoir un ordre. Or dans le cas que tu expliques, il devrait envoyer une requête au serveur pour savoir si le serveur veut lui donner un ordre. Du coup il faudrait sonder très régulièrement le serveur pour être réactif à un ordre qui pourrait être donné une fois par mois comme plusieurs fois par jour. Est-ce un fonctionnement très propre ?
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

Je partais de l'hypothèse que c'était le client qui initialisait une connexion et devait faire quelque-chose en fonction de la réponse serveur (exemple: Windows update où le client va voir ce qui est dispo, puis charge et installe seul)

Si le serveur qui doit aussi pouvoir atteindre le client à tout moment alors il faut que le client se comporte effectivement comme un serveur.
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Donc, je reste sur mon client/serveur TCP.
Concernant ma question au sujet de ReceiveNetworkData(). Quelle est la bonne méthode pour être certain que toutes les données sont bien arrivées ?
J'ai du mal à me rendre compte comment PureBasic gère cela en interne. Il est bien indiqué dans la doc de ReceiveNetworkData() : "If 'Result' is equal to DataBufferLength then more data is available to be read". Mais puisque ReceiveNetworkData() n'est censé être appelé qu'après la réception de #PB_NetworkEvent_Data, ma boucle while n'a peut être aucun intérêt ?
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

Tu peux mettre un buffer plus grand que la taille maxi du message à recevoir et couper le message à la longueur des octets réellement reçus (retournée par ReceiveNetworkData()) donc pas besoin de boucle.

Exemple (basé sur les deux exemples de la doc)

Lancer le serveur, puis le client
Serveur

Code : Tout sélectionner

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

Port = 6832
*Buffer = AllocateMemory(1000)

If CreateNetworkServer(0, Port)
    
   Debug "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 ! " + Str(ClientID)
                    
                Case #PB_NetworkEvent_Data
                    Nb_Octets = ReceiveNetworkData(ClientID, *Buffer, 1000)
                    ;Debug "Reçu: ("+ Nb_Octets +") >>>" + PeekS(*Buffer, -1, #PB_UTF8) + "<<<"
                    Debug "Reçu: ("+ Nb_Octets +") >>>" + PeekS(*Buffer, Nb_Octets, #PB_UTF8) + "<<<"
                    
                Case #PB_NetworkEvent_Disconnect
                    Debug "Client "+Str(ClientID)+" has closed the connection..."
                    Quit = 1
                    
            EndSelect
        EndIf
        
    Until Quit = 1 
    
    Debug "PureBasic - Server: END"
    
    CloseNetworkServer(0)
Else
    MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf

End   
Avec PeekS(*Buffer, -1, #PB_UTF8) tu recois la totalité du buffer.
Avec un buffer plus petit que le plus grand message, je pense que tu devrais effectivement boucler et probablement tester un caractère de fin qui serait à ajouter (EOT ? ETX ?)

Client

Code : Tout sélectionner

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

NewList Jour$()
AddElement(Jour$()) : Jour$() = "Lundi"
AddElement(Jour$()) : Jour$() = "Mardi"
AddElement(Jour$()) : Jour$() = "Mercredi"
AddElement(Jour$()) : Jour$() = "Jeudi"
AddElement(Jour$()) : Jour$() = "Vendredi"
AddElement(Jour$()) : Jour$() = "Samedi"
AddElement(Jour$()) : Jour$() = "Dimanche"

Port = 6832
ConnectionID = OpenNetworkConnection("127.0.0.1", Port)
If ConnectionID
    
    ForEach Jour$()
        SendNetworkString(ConnectionID, Jour$(), #PB_UTF8)
        Delay(1000)
    Next
    
    CloseNetworkConnection(ConnectionID)
Else
    MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf

End   
J'ai peut -être encore répondu à coté, mais ça m'a permis de comprendre des trucs nouveaux
Je n'ai jamais fais d'application client/serveur purement en PB, mais ceci fonctionne.
Tiens, je vais créer mon propre ICQ en PB :mrgreen:
Dernière modification par Marc56 le mar. 12/mai/2020 14:55, modifié 1 fois.
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

En effet ça fonctionne ainsi et la logique se tient :)

En fouinant j'ai aussi trouvé ce lien : http://forums.purebasic.com/english/vie ... 7e1ff8c70b
Il s'avère qu'il y a un soucis lorsque le nombre de bytes retournés par ReceiveNetworkData() est la même que la taille du buffer ET que le paquet envoyé fait aussi cette taille.
Du coup on ne peut pas déterminer si la réception est bien terminée ou s'il en reste, mais si on relance un ReceiveNetworkData(), alors on reste bloqué sur cette fonction qui attends que d'autres données arrivent alors qu'il n'y a plus rien à recevoir.
Et en page 2 une solution qui permet de connaitre le nombre de bytes en attente dans le socket, ce qui permet d'allouer un buffer de la bonne taille directement.
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Demande de conseil pour mise en place client/serveur tcp

Message par Marc56 »

Perso j'aime pas trop mettre des API directes, je préfère utiliser les pièces d'origine certifiés par Fred 8)

Cela dit, comme c'est toi qui fera l'application client et celle du serveur, tu peux fixer d'autorité la taille des chaines envoyées et celle du buffer.

Au besoin, tu mets un caractère de fin (ex: Chr(4) = EOT (End Of Transmission) ou ETX etc, c'est fait pour ne pas être confondu avec le reste et tu le teste à l'arrivée comme dernier caractère du tampon (Right())

Quelque-chose comme ça

Code : Tout sélectionner

Tmp_Buf = PeekS(*Buffer, Nb_Octets -1, #PB_UTF8)
If Right(Tmp_Buf , 1) = Chr(4) : Break : EndIf
(pas testé)

:wink:
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: Demande de conseil pour mise en place client/serveur tcp

Message par tatanas »

Oui je vais peut être faire ça.
Et vu que l'un des clients de ce serveur sera un module d'administration, je pense qu'il requêtera le serveur en webservices puisqu'il ne fera que récupérer des données.
Un pti mix des 2 solutions finalement.
Répondre