Application client-serveur et événements

Programmation d'applications complexes
salutcava
Messages : 34
Inscription : lun. 10/juin/2013 12:01

Application client-serveur et événements

Message par salutcava »

Bonjour/bonsoir,
Client et utilisateur de PureBasic depuis de nombreuses années, je me trouve face à une situation bloquante en programmation client serveur. Et ce à cause de la gestion du réseau par événements dans purebasic.
Je vous présente mon objectif :
avoir une application serveur qui écoute uniquement sur le port 2018 (par exemple)
avoir une application client A qui transmet à intervalles réguliers des données d'une taille L sur le port 2018
avoir une application client B qui transmet à intervalles réguliers des données d'une taille ~L sur le port 2018
A reçoit ce que B envoie grâce à l'application serveur
B reçoit ce que A envoie grâce à l'application serveur
avoir une application cliente C qui reçoit la moyenne des valeurs envoyées par A et B grâce à l'application serveur. Si B n'envoie rien alors C recevra uniquement ce que A envoie. Si A n'envoie rien alors C recevra uniquement ce que B envoie.

Par exemple
A envoie 1020304050
B envoie 60708090A0
C recevra 3848586878 (ou calculera par lui même ces valeurs)

Tout mon problème réside dans la réalisation, coté serveur, de la moyenne. En effet lorsque je lis les événements réseaux, coté serveur, du client A je n'ai la possibilité que plus loin dans mon code de voir s'il y a des données envoyées au serveur par le client B. Du coup je suis bien embêté. La documentation informe qu'il faut appeler ReceiveNetworkData() uniquement après avoir reçu un événement #PB_NetworkEvent_Data. Cette manière de structurer le code par événement m’empêche de réaliser mon objectif.

Dois-je plutot tenter de faire en sorte que la moyenne soit calculée par l'application cliente C?
En y pensant je me dis que placer un header dans le paquet contenant un identifiant attribué par le serveur permettrait de savoir quel client envoie quoi. Mais lorsque A et B enverront des données comment C fera-t-il apres avoir reçu un paquet de A pour savoir qu'il y a un autre paquet en attente de la part de B? Je n'ai jamais eu de mal avec une application réseau mais dans ce cas, devoir structurer avec des evenements me pose de gros soucis. C'est pourquoi je fais appel à votre aide. Je n'attends pas particulièrement un code en réponse, mais plus une idée, une manière de faire....mais pourquoi pas du code si c'est plus simple de répondre ainsi pour vous. Je vous remercie et vous souhaite une bonne journée.
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Application client-serveur et événements

Message par Marc56 »

Je ne suis pas sûr de tout bien comprendre :?

Tout comme un évènement Windows retourne l'évènement ET l'ID la fenêtre concernée,
un évènement réseau retourne les données ET l'ID du client, même s'il y en a plusieurs.

Chaque paquet est identifié et tu peux savoir si un client est connecté ou pas.
Donc un moyen est de détecter si les clients A et B a se sont déconnectés avant de faire les moyennes

Voici un exemple de serveur et client, dérivé de ceux de la doc
(J'ai surtout remplacé les MessageRequester par des Debug pour voir tous les messages ensembles)

Code : Tout sélectionner

Debug "SERVEUR"
InitNetwork()

Port = 6832
*Buffer = AllocateMemory(1000)

If CreateNetworkServer(0, Port)
    Repeat   
        SEvent = NetworkServerEvent()
        ClientID = EventClient()
        Select SEvent
            Case #PB_NetworkEvent_None
                Delay(10)
                
            Case #PB_NetworkEvent_Connect
                Debug "A new client has connected !"
                
            Case #PB_NetworkEvent_Data
                ReceiveNetworkData(ClientID, *Buffer, 1000)
                Debug "Client: " + ClientID + " a envoyé: " + PeekS(*Buffer, -1, #PB_UTF8)
                
            Case #PB_NetworkEvent_Disconnect
                Debug "Client: "+Str(ClientID)+" has closed the connection..."
                ; Quit = 1
                
        EndSelect
    Until Quit = 1
    CloseNetworkServer(0)
Else
    Debug "Can't create the server (port in use ?)."
EndIf

End

Code : Tout sélectionner

;Debug "CLIENT"
InitNetwork()
Port = 6832

ConnectionID = OpenNetworkConnection("127.0.0.1", Port)
If ConnectionID 
  SendNetworkString(ConnectionID, "Données de A" + Chr(0), #PB_UTF8)
  CloseNetworkConnection(ConnectionID)
EndIf

ConnectionID = OpenNetworkConnection("127.0.0.1", Port)
If ConnectionID
  SendNetworkString(ConnectionID, "Données de B" + Chr(0), #PB_UTF8)
  CloseNetworkConnection(ConnectionID)
EndIf
Lance le serveur puis le client, cela te donnera des indications sur les infos échangées.

Si ça peut t'aider (je débute en application réseau en PB)

:wink:

Edit Corrigé suite à suggestion bobby.
Supression If SEvent et ajout Case #PB_NetworkEvent_None : Delay(10)
La charge CPU passe de 25 à 0.17% !
Dernière modification par Marc56 le jeu. 11/oct./2018 16:14, modifié 3 fois.
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: Application client-serveur et événements

Message par boby »

@Marc56 n'ayant pas de waitnetworkevent, je te conseille (coté serveur) de rajouter un case #PB_NetworkEvent_None : delay(xx)
Ca évitera d'avoir un serveur à 100% CPU pour rien.

@salutcava https://www.purebasic.fr/french/viewtop ... 77&start=3
Un exemple fonctionel de relation client serveur...
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Application client-serveur et événements

Message par djes »

Au niveau algo, je pense que tu dois donner un numéro à tes paquets, de façon à pouvoir faire les moyennes dans l'ordre par le serveur. Par exemple si les clients a et b envoient plusieurs nombres à la suite, la moyenne ne sera pas forcément bonne car le tcp/ip ne garantit pas l'ordre d'arrivée des paquets. Pour que cela fonctionne, il faut que tu ajoutes à tes nombres un numéro d'ordre. Par exemple, A envoie 1-123, B envoie 1-456, A envoie 2-765, B envoie 2-876 etc... La moyenne 1 sera (123+456)/2, la moyenne 2 sera (765+876)/2 etc.
salutcava
Messages : 34
Inscription : lun. 10/juin/2013 12:01

Re: Application client-serveur et événements

Message par salutcava »

Merci pour vos réponses marc, boby et djes.
Merci djes pour ton idée de donner un ordre aux paquets des deux clients émetteurs.
Je vais voir si je peux m'en sortir en suivant cette approche.
Merci!
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Application client-serveur et événements

Message par Marc56 »

(Supprimé. Réponse 1 modifiée avec les suggestions de Boby :wink: )
Dernière modification par Marc56 le jeu. 11/oct./2018 16:40, modifié 1 fois.
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: Application client-serveur et événements

Message par boby »

@Marc

Code : Tout sélectionner

SEvent = NetworkServerEvent()
If SEvent 
[...]
EndIf

Code : Tout sélectionner

Debug #PB_NetworkEvent_None
:wink:

C'est vraiment préférable de gérer le delay via l'event (ou plutot le non event) #PB_NetworkEvent_None que dans ta boucle principale, en cas de transfert de gros paquet, si tu delay est dans ta boucle, tu auras ton delay entre chaques ReceiveNetworkData(), alors que si tu met un delay uniquement si il n'y a pas d'activité réseau, bah tant qu'il y a du boulot pour le serveur, il va bosser, sans attendre 10 ms entre chaques écoute réseau. (J'suis d'accord que 10ms c'est vraiment quedal, mais sur un serveur qui se retrouve à gérer beaucoup de connexion, ça doit se sentire à un moment je pense...)
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Application client-serveur et événements

Message par Marc56 »

SEvent = NetworkServerEvent()
If SEvent

Debug #PB_NetworkEvent_None
Merci pour la réponse didactique, ça force à analyser plutôt que recopier :)
Pour une fois ce sont des lignes en trop qui bloquaient :P
Effectivement pour traiter #PB_NetworkEvent_None (= 0) il faut d'abord entrer dans la boucle Select, donc SEvent <> 0. Logique!
Ça fonctionne bien maintenant, tous mes programmes réseaux tournent à environ 0.17% de CPU contre 24% avant.

:wink:
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Application client-serveur et événements

Message par djes »

Pour ton problème de qui envoie quoi, il suffit d'imaginer une conversation à 4 par courrier : on met sur l'enveloppe le nom du destinataire, de l'expéditeur et la date. Pour transférer un courrier, tu le joins en entier. De cette manière, le destinataire peut tout déduire.

Pour ton problème de moyenne qui ne se fait que si a et b ont répondu, il faut forcément que cela soit rattaché à autre chose de commun, pour que les réponses soient coordonnées. Soit un numéro d'ordre, soit un numéro extérieur ou un signal commun. C'est difficile de dire mieux sans savoir à quoi ça se rapporte.
salutcava
Messages : 34
Inscription : lun. 10/juin/2013 12:01

Re: Application client-serveur et événements

Message par salutcava »

Voici plus d'informations sur le problème que je rencontre. Lors de mon tout premier poste j'ai essayé de simplifier au maximum mon vrai probleme.
Il se trouve que les données envoyées sont des données audio. Et donc la moyenne n'est pas une moyenne mais de quoi "mixer" les données audio.
Voilà tout.
Peut etre que le mix (la moyenne) devrait se faire coté serveur du coup?
Toujours est-il que j'ai ajouté en entete de mes données audio un identifiant unique aux émetteurs , comme suggéré dans une des réponses proposées.
Je vais voir comment je peux m'en sortir avec cette approche.
(je n'ai pas avancé plus ayant manqué de temps....(eh oui Black OPS 4 est sorti... :( )
salutcava
Messages : 34
Inscription : lun. 10/juin/2013 12:01

Re: Application client-serveur et événements

Message par salutcava »

Bonjour/Bonsoir,
Je reviens vers vous pour vous donner des nouvelles :D
De la manière que j'envisageais les choses...ca aurait été compliqué d'arriver à mes fins. Il aurait fallu identifier les émetteurs des packets audio et calculer leur durée et mixer le son etc etc
HEUREUSEMENT que le codec son que j'utilise gère le multistream...du coup tout va bien le problème est résolu. Les paquets arrivent les uns à la suite des autres et tout est géré automatiquement...Ahhhh les library...qu'est ce qu'on ne ferait pas sans elles....Cependant faire les choses par soit même à son petit coté stimulant qui ne me deplait pas :)
Les paquets arrivent donc les uns à la suite des autres et le multistream est géré sans soucis.
Merci à vous pour vos réponses, je vous aime. Bisous!
Vive Purebasic, je kiffe depuis des années!
Répondre