SendNetworkData?

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

SendNetworkData?

Message par poshu »

Salut,

Pour les besoins de ma ré-implémentation de FCGI, je me suis tourné vers les fonctions réseau natives de PB.
J'ai des résultats... Que je ne comprends pas : quand il envoie un gros fichier (> 64 ko), l'application FCGI envoie au serveur web une série de "records", des packets contenant le fichier saucissonné en petits morceaux. Ces packets sont envoyés successivement et, si je ne ralenti pas le processus avec un delay(1) entre chaque salve, alors j'obtiens un résultat variable, mais toujours corrompu :

Image

(Vous pouvez tester par vous même ici, le delay(1) est ligne 188)

J'ai parcouru la doc sans trouver d'explication et je ne suis pas un habitué des fonctions réseau de pure, donc :
_Pourquoi ce résultat? Est-ce attendu? Est-ce un bug?
_Y-a-t'il un moyen plus efficace qu'un delay(1)? C'est vraiment très moyen niveau perf et dans des cas extrêmes (connexion application fcgi/serveur lente par exemple), ça ne suffirait probablement pas.
Dernière modification par poshu le ven. 21/déc./2018 16:24, modifié 1 fois.
Mesa
Messages : 1098
Inscription : mer. 14/sept./2011 16:59

Re: SendNetworkData?

Message par Mesa »

Ça vaudrait le coup de mettre SendNetworkData dans un thread.

Le fil de mk-soft est interressant avec son module: Module NetworkData - Send strings and data over 64kb
https://www.purebasic.fr/english/viewto ... etworkData

M.
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: SendNetworkData?

Message par boby »

si tu debug "SendNetworkData(*Request\ClientID,*Packet + Position,#__MULTIRECORDSIZE + #__HEADER_SIZE" tu te tape du -1 (impossible d'envoyer le packet) mais tu décale quand même ton positionement dans ton buffer "Position + #__MULTIRECORDSIZE + #__HEADER_SIZE" du coup tu n'envois pas tout, du coup tu recois nimporte quoi ! (spèce de noob)

Bon... j'ai la flem d'installer un xampp du coup c'est un résulta de debug non testé (mais je pense que c'est ça) donc je ne suis pas affirmatif à 100%, mais juste pour le plaisire de t'insulter de noob j'me permet un débug à l'aveugle ;)

PS : le debug peut possiblement ralentire assez le bouzin pour t'éviter le bug...
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: SendNetworkData?

Message par G-Rom »

Salut Poshu.

Le procotole TCP est limité dans la taille de ces paquets, tout comme l'udp. à toi, de ton coté de créer un protocole par dessus le TCP, je m'explique , pour chaque message envoyé , tu colles un "id" dans chaque début de paquet :

Code : Tout sélectionner

#PACKET_SIZE = 4096

Enumeration
  #PROTOCOL_BEGIN_SEND_MESSAGE    ; [ ID ] [ CHECKSUM ] [ SIZE ( 4 BYTES ) ] [ DATAS ] 
  #PROTOCOL_SEND_MESSAGE          ; [ ID ] [ CHECKSUM ] [ DATA ]
  #PROTOCOL_END_MESSAGE           ; [ ID ] [ CHECKSUM ] [ DATA ]
EndEnumeration


Structure Packet  ;--
  id.c            ;  |---> 4096 ! 
  *data           ;  |
EndStructure      ;--
le protocole étant le TCP , tu n'auras pas besoin de créer un système de "reliabilité" ( ack , etc... ) pour t'assurer la bonne réception d'un paquet, le TCP le fait pour toi , contrairement à l'UDP.
donc, à l'envois , tu "découpes" ton message si il est plus gros que 4096 ( valeur arbitraire , mais < que 65535 !) en plusieurs paquets. tu valides à la réception si tu as toutes les parts du message, et que le checksum correspond à tes datas.

Rien de bien sorcier donc, à toi donc, de bien mettre en place un protocole simple et robuste en place, tu pourras viré ton delay par la suite, pense néanmoins à ne pas saturé ta bande passante, si c'est le cas, faudra temporisé l'envois de data.
poshu
Messages : 1138
Inscription : sam. 31/juil./2004 22:32

Re: SendNetworkData?

Message par poshu »

@Mesa : en fait, tout est déjà threadé : c'est justement pour ça que je ré-implémente fcgi; la lib a l'air très intéressante, je vais lire ça, merci :D

@G-Rom : je sais bien, mais j'utilise un protocol normalisé, je peux pas inventer des trucs par dessus...

Edit : ok, j'ai changé le code en prenant en compte le soucis soulevé par boby, et ça marche sous windows maintenant; j'ai encore un soucis sous mes distribs linux (Elementary OS + Nginx et Debian + Nginx) mais j'ai une piste maintenant.
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: SendNetworkData?

Message par G-Rom »

y a rien à inventé par dessus, juste à mettre en place un mécanisme de bonne réception & envoie de donné , peu importe la norme sous jacente...
le principal , c'est de pouvoir envoyer de la data correctement, et le client de reconstitué le message à l'arrivé correctement aussi.

là, tu envois des données en bordel sans contrôler si l'envois à bien été effectué avec SendNetworkData() :
Renvoie le nombre d'octets qui ont été effectivement envoyés.
S'il n'est pas égal à 'LongueurMemoireTampon', la mémoire tampon de réception de l'utilisateur est probablement pleine.
Si rien n'a pu être envoyé alors 'Resultat' sera égal à -1.
et aucun contrôle coté réception , il peut recevoir des données partielles , le client ne le saura pas si il y a un echec coté serveur.
je ne vais pas te codé le truc complet , mais voici l'idée :

Code : Tout sélectionner

#PACKET_SIZE = 15

Enumeration
  #PROTOCOL_BEGIN_SEND_MESSAGE      ; [ ID ] [ CHECKSUM ] [ SIZE ( 4 BYTES ) ] [ DATAS ] 
  #PROTOCOL_SEND_MESSAGE            ; [ ID ] [ CHECKSUM ] [inused] [ DATA ]
  #PROTOCOL_END_MESSAGE             ; [ ID ] [ CHECKSUM ] [inused] [ DATA ]
  #PROTOCOL_BEGIN_END_SEND_MESSAGE  ; [ ID ] [ CHECKSUM ] [ SIZE ( 4 BYTES ) ] [ DATAS ] 
EndEnumeration

#HEADER_SIZE = 9


Structure Packet  ;--
  id.c            ;  |---> 4096 ! 
  checksum.l      ;  |
  size.l
  *data           ;  |
EndStructure      ;--

Global NewList *PacketToSend.Packet()


Procedure SendMessage(*data, size.l)
  
  Protected checksum.l = 0 ; fct de checksum ici !
  
  ; le paquet est trop gros
  If size + #HEADER_SIZE > #PACKET_SIZE
    
     AddElement(*PacketToSend())
     
     *PacketToSend()          = AllocateStructure(Packet)
     *PacketToSend()\id       = #PROTOCOL_BEGIN_SEND_MESSAGE
     *PacketToSend()\checksum = checksum
     *PacketToSend()\size     = #PACKET_SIZE - #HEADER_SIZE
     
     *PacketToSend()\data     = AllocateMemory(*PacketToSend()\size)
    
     CopyMemory(*data, *PacketToSend()\data , *PacketToSend()\size)
    
    sizeToSend = (size-#HEADER_SIZE) - (#PACKET_SIZE - #HEADER_SIZE)
    nbPacket   = sizeToSend / (#PACKET_SIZE - #HEADER_SIZE)
    offset     = #PACKET_SIZE - #HEADER_SIZE
    
    If nbPacket > 1 ; il y a plus d'un paquet à envoyer
      
      ; on génère les paquet intermédiaire 
      For i = 0 To nbPacket-2
        
        AddElement(*PacketToSend())     
       *PacketToSend()          = AllocateStructure(Packet)
       *PacketToSend()\id       = #PROTOCOL_SEND_MESSAGE
       *PacketToSend()\checksum = checksum
       *PacketToSend()\size     = #PACKET_SIZE - #HEADER_SIZE
       *PacketToSend()\data     = AllocateMemory(#PACKET_SIZE - #HEADER_SIZE)
        CopyMemory(*data+offset, *PacketToSend()\data , #PACKET_SIZE - #HEADER_SIZE)
        
        offset + (#PACKET_SIZE - #HEADER_SIZE)
        
      Next
      
      ; le paquet de fin
      AddElement(*PacketToSend())     
       *PacketToSend()          = AllocateStructure(Packet)
       *PacketToSend()\id       = #PROTOCOL_END_MESSAGE
       *PacketToSend()\checksum = checksum
       *PacketToSend()\size     = size - offset
       *PacketToSend()\data     = AllocateMemory(#PACKET_SIZE - #HEADER_SIZE)
        CopyMemory(*data+offset, *PacketToSend()\data , *PacketToSend()\size)
      
    Else 
      ; le paquet de fin
       AddElement(*PacketToSend())     
       *PacketToSend()          = AllocateStructure(Packet)
       *PacketToSend()\id       = #PROTOCOL_END_MESSAGE
       *PacketToSend()\checksum = checksum
       *PacketToSend()\size     = size - offset
       *PacketToSend()\data     = AllocateMemory(#PACKET_SIZE - #HEADER_SIZE)
        CopyMemory(*data+offset, *PacketToSend()\data , *PacketToSend()\size)
    EndIf 

    
  Else
    
    ; le message de base est plus petit que la taille d'un paquet :
    AddElement(*PacketToSend())
     
     *PacketToSend()          = AllocateStructure(Packet)
     *PacketToSend()\id       = #PROTOCOL_BEGIN_END_SEND_MESSAGE
     *PacketToSend()\checksum = checksum
     *PacketToSend()\size     = size
     *PacketToSend()\data     = AllocateMemory(#PACKET_SIZE - #HEADER_SIZE)
    
     CopyMemory(*data, *PacketToSend()\data , size)
    
    
    
    
  EndIf   
  
  
EndProcedure




; tu envois ton message entier ici !
SendMessage(?message,(?tag-?message))

; juste pour le controle 
p = 0
ForEach *PacketToSend()
  Debug "paquet numero : " + Str(p)
  Debug "id : " + Str(*PacketToSend()\id )
  Debug "size : " + Str(*PacketToSend()\size)
  For i = 0 To *PacketToSend()\size - 1
    Debug "data : " + PeekA(*PacketToSend()\data+i)
  Next 
  Debug ""
  p+1
  
  ; tu fait le sendnetwork ici !
Next


DataSection
  message:
  Data.a 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38  
  tag:
EndDataSection



Les messages trop gros, peu importe ce que tu veut envoyer, est découpé correctement.
cowpowah
Messages : 41
Inscription : mer. 02/juin/2010 12:41

Re: SendNetworkData?

Message par cowpowah »

G-Rom a écrit :Le procotole TCP est limité dans la taille de ces paquets
Salut G-Rom,

Le protocol TCP ne découpe pas lui-même les paquets? (découpe coté serveur et assemblage coté client)
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: SendNetworkData?

Message par boby »

Le protocole TCP s'assure que ce qui est envoyé est la même chose que ce qui est reçu. La découpe des datas a envoyer, c'est ton boulot.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: SendNetworkData?

Message par djes »

cowpowah a écrit :
G-Rom a écrit :Le procotole TCP est limité dans la taille de ces paquets
Salut G-Rom,

Le protocol TCP ne découpe pas lui-même les paquets? (découpe coté serveur et assemblage coté client)
En fait on fait souvent un abus de langage en parlant de paquets. Les véritables paquets sont gérés à un niveau bas de façon transparente, par l'Internet Protocol (IP). Transmission Control Protocol (TCP) s'occupe de s'assurer que tout arrive à destination, et va donc gérer toute la partie vérification/renvoi, par un dialogue entre serveur et clients. À un niveau plus élevé encore, le nôtre, quand on découpe un fichier pour l'envoyer grâce à TCP/IP, on devrait plutôt parler de segments, fragments, blocs, chunks de données.
(Et encore, je vulgarise, parce que dans la réalité c'est bien plus compliqué)
cowpowah
Messages : 41
Inscription : mer. 02/juin/2010 12:41

Re: SendNetworkData?

Message par cowpowah »

C'est bien ce qu'il me semblait, il y deux découpages: un automatique et un manuel :roll:

Je suppose que ça permet de faire (entre autre) du load balancing pour les gros serveurs...
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: SendNetworkData?

Message par boby »

Non, y'a que un "découpage", le protocol TPC fait un calcul basé sur les data envoyé, il colle résultat en fin de tram (CRC), le client recois, fait le même calcule et compart avec le résultat inscrit en fin de tram, si c'est identique c'est qu'il a bien recu les datas, sinon il demande à l'emeteur de réenvoyer la trame. TCP s'occupe uniquement de la bonne transmission/réception des données via réseau.

La découpe des datas, c'est toi et toi seul qui le gére.
cowpowah
Messages : 41
Inscription : mer. 02/juin/2010 12:41

Re: SendNetworkData?

Message par cowpowah »

En fait si :wink: Le protocol TCP/IP découpe les 65536 octets, que tu as découpé :roll:, en segments de 1492 octets (de façon totalement automatique et invisible)

(sur wiki, voir MTU et l'exemple)

C'est pour ça que j'étais étonné de cette découpe manuelle à 65Ko, mal gérée on perd les avantages du TCP/IP.
Je pense, comme G-Rom, que c'est le problème de Poshu: ses paquets arrivent dans le désordre quand ils sont envoyés trop vite, et sans protocole pour les numéroter...
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: SendNetworkData?

Message par G-Rom »

Je pense, comme G-Rom, que c'est le problème de Poshu: ses paquets arrivent dans le désordre
je ne pense pas cela. les paquets arrivent dans l'ordre en TCP, c'est d'ailleurs le but du protocole , et c'est aussi une faiblesse dans la vitesse avec les mécanisme de handshake... mais ce n'est pas le sujet.
D'ailleurs receivenetworkdata() , ne reçois pas de "paquet" , mais recois de la data QUAND les paquets sont reconstitué en totalité ou en partie, je ne vais pas rentré dans plus de détails ici.
Le problème de poshu, il flood certainement ca carte réseau en envois, d'ou mon idée de découpé , puis d'envoyer tranquillement les datas et de les reconstituer à la fin, peu importe la data envoyé. d'ailleurs le delay() ne résoud t'il pas en partie le problème ? si oui, c'est qu'il flood & le délais ne sera valable que sur sa machine. pas sur une autre.

Bon réveillon à tous.
cowpowah
Messages : 41
Inscription : mer. 02/juin/2010 12:41

Re: SendNetworkData?

Message par cowpowah »

Ah oui, c'est possible aussi... Très possible même, vu le résultat.

Je sais pas comment fonctionne précisément SendNetworkData() mais il pourrait pas vérifier comme ça:

Code : Tout sélectionner

Progress = SendNetworkData(*Request\ClientID,*Packet + Position + SentData,#__MULTIRECORDSIZE + #__HEADER_SIZE - SentData)

If Progress <> (#__MULTIRECORDSIZE + #__HEADER_SIZE - SentData)
  Debug "(FinishReponse()/3) - Erreur lors de l'envois des données, données envoyées: " + Str(Progress) + ", cible: " + Str(#__MULTIRECORDSIZE + #__HEADER_SIZE - SentData)
EndIf
Est-ce que 'Progress' c'est ce qui est envoyé à la carte réseau, ou par la carte réseau?


ps: bonne année à tous! :D
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: SendNetworkData?

Message par boby »

de façon totalement automatique et invisible
Oui donc on s'en fout quoi. Le seul interet de TCP c'est le control d'erreur... On utilise TCP pour envoyer des données sans se poser la question "est-ce que tout est bien arrivé".
Je pense, comme G-Rom, que c'est le problème de Poshu: ses paquets arrivent dans le désordre quand ils sont envoyés trop vite, et sans protocole pour les numéroter...
Non, son problème c'est qu'il ne vérifiait pas la quantitée de data qu'il recevais avec receivenetworkdata mais qu'il faisait avancer son "curseur" dans son buffer, du coup le fichier envoyé n'était que partielement reconstitué.
Returns the number of bytes received. If 'Result' is equal to DataBufferLength then more data is available to be read. If an error occurred on the connection (link broken, connection close by the server etc...) 'Result' will be -1.
Répondre