ÉVITER QUE LES PAQUETS SE MÉLANGE LORS DE L'ENVOIE AVEC WINSOCK

cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009 - 5 août 2003 à 08:46
tbbuim1 Messages postés 940 Date d'inscription jeudi 20 février 2003 Statut Membre Dernière intervention 3 février 2011 - 31 mars 2005 à 15:51
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/8147-eviter-que-les-paquets-se-melange-lors-de-l-envoie-avec-winsock

tbbuim1 Messages postés 940 Date d'inscription jeudi 20 février 2003 Statut Membre Dernière intervention 3 février 2011 9
31 mars 2005 à 15:51
Ok j'ai capté comment l'utiliser, mais ça marche pas top :(
J'ai des messages qui se concatènes qd mm mais pas systématiquement :( Donc ce n'est pas une solution fiable.
C'est qd mm incroyable qu'il n'y ait pas de moyen de faire ça sans renvoyé un message du serveur!
tbbuim1 Messages postés 940 Date d'inscription jeudi 20 février 2003 Statut Membre Dernière intervention 3 février 2011 9
29 mars 2005 à 16:03
Bref, quelqu'un aurait-il une solution claire, nette et précise qui fonctionne?
tbbuim1 Messages postés 940 Date d'inscription jeudi 20 février 2003 Statut Membre Dernière intervention 3 février 2011 9
29 mars 2005 à 15:31
Ca aurait été super top over méga génial avec une petite source de rien du tout pour faire un tout petit exemple...
Ca à l'air pas mal, mais ça manque de commentaires explicatif, de ce fait, je n'arrive pas à m'en servir.
Quand doit on se servir de la fonction vider_Pile?
Qd je fais Pile.Add "données" à la place de SendData, il y a une erreur qui me dit Object Required...
Quand tu dis, éviter que les paquets se mélangent, ça veut dire quoi? Parce que moi les paquets se concatènent si je les envoi à la suite, et j'aimerais qu'ils me les envoi un par un, est-ce ta source sert à faire ça? Merci répondre.
kimmelf2 Messages postés 267 Date d'inscription lundi 22 septembre 2003 Statut Membre Dernière intervention 27 novembre 2005
26 sept. 2003 à 00:13
pour resumer (le principe de base) :
tu fais un truc du genre

sck1 et sck 2 = controles winsock

sck1.listen

sub sck1_connectionrequest(byval id as long)
sck2.accept id
end sub

c'est sck1 qui recoi la demande de connection mais c'est sck2 qui l'accepte

et dans ton exemple, tu utilise une collection de winsock plutot qu'un nombre predefini (ca je le savais)

la ou je bloquais, c'est que je croyais que c'etais le winsock qui recevais le connectionrequest qui devais accepter l'IDRequest

mais si je peux l'accepter par un autre winsock ... ca deviens beaucoup + simple !
cs_sub-zero Messages postés 98 Date d'inscription mercredi 22 novembre 2000 Statut Membre Dernière intervention 12 juillet 2005
25 sept. 2003 à 10:16
personnellement j'utilise uniquement des classes (ajouter winsock.ocx comme référence et non comme composant) ce qui permet d instancier les object du genre dim mysock as new winsock


pour gérer ton pb, tu crée un objet winsock ds ta classe
private withevents sock as new winsock

exemple d un serveur d authentification
....
m_type = srvIdent
sock.close
sock.Bind port, ip (on peur binder l IP de son choix en case de plusieurs IP)
sock.Listen
...


et tu passes le request ID a la classe qui va gérer ca.( ici c un exemple d un serveur multi tache)

Private Sub sock_ConnectionRequest(ByVal requestID As Long)
'***Procédure de traitement des requetes de connexion****
Dim t As Object
If mycol.Count < Maxclients Then
nb = nb + 1
Select Case m_type
'//serveur d identification
Case srvIdent:
Set t = New CServeurLogin
mycol.Add t, Hex(t.ServeurIDent)
t.AffectSocket requestID, Me, timeout, m_msgA, m_filtre

'//serveur de messagerie
Case srvChat:

'//serveur de recherche
Case srvFinder:

'//serveur de fichiers
Case srvBrowser:
Set t = New CServeurBrowser
mycol.Add t, Hex(t.ServeurIDent)
t.AffectSocket requestID, Me, timeout
End Select
End If
Set t = Nothing
End Sub

et dans la classe CserveurLogin
un autre object withevents sock

Public Sub AffectSocket(sID As Long, srv As CServeur, Optional sTimeOut As Long 4000, Optional msg As String, Optional filtreparts As Boolean True)
Dim flag As Boolean
If sock.State <> sckClosed Then sock.Close
sock.Accept sID
....
end sub



un port a l'écoute peut accepter un nbre presque illimité de clients à condition d opter pour un système multithreads. La destruction de la collection ou de l objet via la classe principal impose la fermeture du port.

j obtiens des performences très intéressantes avec ce procédé.
kimmelf2 Messages postés 267 Date d'inscription lundi 22 septembre 2003 Statut Membre Dernière intervention 27 novembre 2005
25 sept. 2003 à 02:05
je resume en + claire (du moins j'esperes)

B veut chatter avec A qui est deja connecte

- B se connecte sur un port fixe predefini (le port serveur) de A (ce port est en ecoute)
- le socket sur le psA recupere l'IP et le port de B puis se remet en ecoute pour choper de nouveaux arrivants
- A etabli une connexion depuis un de ses ports libre (p4A) vers l'IP et le port de B qui ont ete recuperes

En fait, B se presente a A par une connexion sur psA
Puis A cree la connexion qui sera vraiment utilisee pour chatter

en schema :

Cote A Cote B
(IPA, psA) <----------- (IPB, p1B) Connection etablie par B

A recupere IPB et p1B, puis remet psA en ecoute
A determine p4A

(IPA, p4A) -----------> (IPB, p1B) Connection etablie par A



c'est un peu tire par les cheveux !!!


sinon, autre methode :
B se connecte a A sur psA
A determine un port libre (p6A) et envoi p6A a B
B se deconnecte de psA
B se reconnecte a A sur p6A
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
24 sept. 2003 à 17:38
En fait pas besoin d'utiliser un port different à chaque connexion ! Un port ne peut être qu'une fois en listening mais pas en communication !
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
24 sept. 2003 à 08:43
j'ai vite fais ragardé mais regarde ds l'aide de msdn comment ils font pour faire de la multi-connexion en TCP (avec des groupes de controles) peut etre que ça t'aidera, je regarderais ton post plus en detail un peu plus tard ;)
kimmelf2 Messages postés 267 Date d'inscription lundi 22 septembre 2003 Statut Membre Dernière intervention 27 novembre 2005
24 sept. 2003 à 01:28
hey !

j'ai juste une petite question dans un autre domaine : comment vous faites pour "rediriger" (j'entend par la changer de port) une connexion lors de winsock_connectionrequest ???

car un nouvel intervenant sur un chat doit se voire attribuer un socket sur un port libre sur la machine distante (du moins je pense) hors il ne peux pas determiner celui ci de lui meme, c'est uniquement la machine distante qui peux l'attribuer.

moi j'avais fais un "protocole" barbare :
notations :
machine A : machine deja connectee
machine B : nouvel intervenant
IPA = Ip de la machine A
IPB = IP de la machine B
psA = port "serveur" de la machine A
p1A = un port sur la machine A
p2A = un autre port de la machine A
...
psB, p1B, p2B ... idem mais sur la machine B

sur psA et psB, un socket en ecoute permanante (d'ou le terme "port serveur")
A a deja 3 connexion : p1A, p2A, p3A

B determine un port libre : p1B
B, depuis p1B, se connecte a IPA sur le port psA
A recupere l'IPB et p1B, se deconnecte sur psA et se remet en ecoute
A determine un port libre : p4A
A, depuis p4A, se connecte a IPB sur le port p1B

complique .....

vos avis ?? des suggestions ?? merci d'avance
cs_sub-zero Messages postés 98 Date d'inscription mercredi 22 novembre 2000 Statut Membre Dernière intervention 12 juillet 2005
14 sept. 2003 à 21:15
la solution réside dans la modification directe des propriétés du handle du socket ;)

personnellement j utilise l API setsockopt pour désactiver l optimisation nodelay du protocole TCP (algo de nagel), j active le linger et j augmente la taille du tampon en envoi et réception.

couplé à une solution de splitage des paquets par caractère ésparateur, les résultats sont concluant.
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
17 août 2003 à 14:30
C'est forcement quoi ? ^^
Je vois pas en quoi c'est mal... au contraire !

Déjà le fait de changer de socket permet de changer le port d'écoute... ce qui permet entre autre d'avior une meilleure sécurisation... Puis bon, ouvrir un socket ne présente pas de grande difficulté en .NET ^^ (oui l' API de .NET est plutôt pas mal niveau socket, mais elle bugge concernant le contrôle winsock par contre ! :-/)

Vilà vilà...
Mais sinon y a encore mieux si tu veux pas ouvrir de deuxième socket... tu rajoute un seul octet pour indiquer l'opération en cours, par exemple, admettons que tu fais un truc de chat où tu peux aussi envoyer des fichiers, tu fais que tu on premier caractère correspond à l'action en cours, c'est à dire, par exemple si je parle le premier caractère serait ! ce qui pourrait donner:

!Ce que je dis

Et par exemple pour un chuchot, (il faut donc un parametre supplémentaire) le 1er serait ? et pour trouver la longueur tu pseudo du destinataire tu code en hexadécimal... (beaucoup mieux ! :))


De toutes façons y a plusieurs méthodes correctes

@++
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
15 août 2003 à 19:25
aaaa mais c mal ca ;) fo essayer de le faire avec un seul si possible et ça l'est forcement vu que les softs pro et meme d'autres le font ;)
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
15 août 2003 à 16:32
Si je transfert un fichier j'ouvre un second socket moi.... (avec une méthode un peu spéciale....)
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
15 août 2003 à 13:50
wai mais si tu envoie un fichier tu peut pas te permettre d'empecher l'envoi de ton caractère sil est contenu ds le fichier...

j'ai pensé à une autre technique


tu envoie en entete la taille de la trame

genre 10:CHAT:salut8OPENCHAT

comme ça il te suffit de découper à chaque fois du nombre de caractère suivants et tu retombera pile au début de la trame suivante donc ça devrait aller... je teste ça.... sinon pour mon ancienne technique mis à part que le parsging (parcours) de la chaine coté server et la suppression des inhibiteur soit lourde, ya un autre problème: CHAT:\\\\; ==> ce message inihibe mon caractère de fin... en fait le dernier caratère du message ne dois pas etre un sinon ça marche po...

donc je teste la nouvelle technique qui me semble encore mieux
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
15 août 2003 à 13:17
Beuh... Je vois aps ce que vous y reprochez à mon système.... Il a l'avantage de faire des paquets simples à interpreterDe plus j'empêche les gens d'envoyer mon caractère de séparation tout simplement.... Puis aussi bien je me fous d'envoyer 4/5 octets supplémentaires vu que 1) Même pour un 56K c'est pas énorme et 2) Mon logiciel est plutôt pour des connexions ADSL donc...
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
15 août 2003 à 00:17
désolé mais mon caratère inhibeur n'a pas l'air de passer dans le forum, c'est un backslash, fo le mettre devant le ";" pour quil ne soit pas pris en compte lors du découpage
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
15 août 2003 à 00:15
je suis tout à fais d'accord avec ton l'ensemble de ton dernier post (sans rancune aucune ;) )

sinon, ta technique est ok, théoriquement elle est sencé fonctionner impec, mais je pense qu'avec la mienne on peut éviter le découpage des trames par nous et laisser ce travail à winsock

ce que je fais exactement coté serveur :
j'ai une chaine de char ; lors d'un dataarrival, je met tout ce que je recois ds la chaine
ensuite je la parse : si je trouve des ";" qui ne sont pas précédés par un "", je selectionne la partie de la chaine située entre cet ";" et le ";" précédant ou le début de ma chaine; j'envoie alors ce fragment de chaine a une fonction qui se chargera de faire le boulot avec une trame nickel. ensuite je vide ma chaine et si il y restait des éléments restant après le dernier ";", je les remet dans ma chaine. comme ça ils seront traités la fois d'après dans le cas ou la trame est découpée par winsock.

coté client je peut donc me permettre d'envoiyer mes trames ainsi : senddata trame1 & ";" & trame2
sans me poser de question et je saurais que les trames seront redécoupés à l'arrivée; si une tramer contient ";", il suffit de mettre le caractère inhibeur devant (";") et ainsi il se sera pas pris en compte lors du découpage des trames coté serveur.

voilou a+
Greengold Messages postés 57 Date d'inscription mercredi 16 octobre 2002 Statut Membre Dernière intervention 31 mars 2004
14 août 2003 à 23:52
Bon en fait j'ai relu ton post et c vrai que je me suis un peu amballé :) Mais bon, toi de ton coté tu n'as pas été suffisament rigoureux.

plusieurs personnes on proposé des solutions techniques, et toi qd tu parles d'une technique tu ne dis pas à qui elle appartient... ça va pas.

*** le coup du timer de 1ms et su sleep de 1ms aussi je trouve que c'est un peu au petit bonheur la chance genre peut etre que la trame aura le temps d'etre envoyée avant de se faire concatenée avec une autre.

Si tu trouves qu'il y a une meilleure solution, expose là direct, en plus tu sais que ça marche et tu dis "au petit bonheur la chance", non là, ça passe pas, tu peux dire que c pas optimisé ou ce que tu veux mais pas un tel commentaire.

*** la technique de Greengold pour les entetes de trame, ça bouffe de la bande passante.

Là c du foutage de gueulle qd meme, admet-le, meme sur un 56K, ça n'a aucune incidence... et encore moins sur réseau local qui est à 100 Mbits...

Pour l'histoire de la séparation des paquets... moi j'ai trouvé que les trames winsoks sont limitées à environ 8 Ko. Donc on peut parfaitement définir une limite < à 8 Ko. Au-delà, le paquet est envoyé en plusieurs fois.

Et Pour finir, pour l'histoire du split et caractère de fin : t'as pas fais gaffe que sur le data arrival coté serveur, j'analyse mes en-tetes de trames (différents de délimiteur !!) , c-a-d, les 3 premiers caractères, donc ton exemple : "blablaftmdtmblabla", coté client je fais un senddata de "DTM" & "blablaftmdtmblabla", puis un senddata de "FTM". Pour moi c la solution ultime. Impossible qu'il y ait une erreur. Relie bien mon exemple, je définie des trames à taille personnalisée, et je gére le dépassement de la limite de capacité des trames avec mes en-tetes. Voilà !

Donc, si tu veux faire de la critique de sources, il va falloir être plus rigoureux... et par exemple faire des test avant de trop s'avancer.
Enfin, quoi qu'il en soit, j'ai absolument rien contre toi, malgré les apparences (trompeuses), sans rancune ?
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
14 août 2003 à 23:12
oula oula calmos j'ai jamais voulu etre méchant ni quoi que se soit calme toi... toutes les methodes ici se valent et fonctionnent bien, seulement chacune à ses avantage et ces defaut, je me contentais uniquement de les énumérer sans arrière pensée... t'énerve pas ;)

en plus de ca je ne crois pas avoir fais un commentaire non contructif étant donné que j'ai essayé d'aporter une amélioration à une technique , en l'occurence celle de Benj1105 (et pas la tienne en plus, mais ça reste du split). alors si t'accepte pas qu'on puisse critiquer (en bien et en mal) tes methodes, c'est pas de ma faute, même si je m'y suis peut etre mal pris dans mon language. désolé mais je vais pas non plus me prendre le choux et etre super poli dans un forum, on est là pour s'entraider pas pour se faire des courbettes...

bon mis à par ça :
pour les timer : utiliser les timer ou les sleep alors que l'ont peut faire autrement je trouve ça porc personnelement après chacun pense ce qu'il veut

pour l'histoire du split et caractère de fin : ce que je voulais dire, c'est pour ton exemple, si un chateur tape "blablaftmdtmblabla" dans sa fenetre, avec ta technique, ca devrait (je pense) faire 2 messages distinct (2 fois blabla); je veut bien que ça soit très rare mais bon dis moi si j'ai tord. d'ou mon idée de mettre un seul caratère entre 2 messages et de l'inhiber par un autre caratère dans le cas ou l'utilisateur le rentre dans la fenetre de chat

*** tu peut pas choisir toi meme de la decouper à telle taille :
j'ai lu sur un site que un utilisateur peut choisir la taille maxiamle de ses trames sous windows, donc j'ai pas vérifié mais c t uniquement pour cela que je disait ca ; si winsock sépare ses paquets automatiquement, ca doit etre fais pour donc mieux vaut le laisser faire et utiliser une autre technique.

<< tu verras que je n'utilise pas de délimiteur... Ta solution de mettre le délimiteur à la fin n'a aucun sens >> toit tu met tes "délimiteurs" au début sous la forme dtm stm ftm, ca reviens au meme que moi en mettant un ";" à la fin nan ?

aller a+ et reste zen
Greengold Messages postés 57 Date d'inscription mercredi 16 octobre 2002 Statut Membre Dernière intervention 31 mars 2004
14 août 2003 à 19:39
En réponse au commentaire de docteurre :

*** Utiliser des en-tetes de trames bouffe de la bande passante :

Mes en-tetes sont définies sur 3 octets --> OULALA, 3 octets dans une trame, mais ça noie absolument toute la bande passante, avec cette méthode, il faut une connexion adsl 1024 ou T1 sinon c pas la peine...

*** tu peut pas choisir toi meme de la decouper à telle taille :

Eh ben si ! je le peux, si tu veux pas être enmerdé tu limites tes trames à 6 Ko et puis voilà. Il faut savoir que dans un logiciel comme un chat, les plus gros transferts sont les messages, mais dans tous les chats que j'ai utilisé, toutes les zones de texte d'écriture des messages sont limitées en cararctères, donc pas de soucis de dépassement de capacité de la trame à envoyer.

*** le pb avec le split que par exemple si un chateur tappe ton caractère de fin :

Le ";" je l'utilise pour les messages systèmes (internes à mon appli) donc pas de pb. Si tu regardes la première partie de mon explication, tu verras que je n'utilise pas de délimiteur... Ta solution de mettre le délimiteur à la fin n'a aucun sens... C'est à se demander si tu t'es déjà servi du split et si tu as compris le principe de traitement des trames coté serveur...

*** si tu as besoin d'envoyer plusieurs packet rapidement tu perd 1ms par envoie au final ç peut faire beaucoup surtout si tu bosse en local :

OULALA, mon Dieu !! Une milli seconde, mais c énorme !!! Pour ta gouverne, si on se base sur la théorie, en une seconde, j'envois 1000 trames... T'as encore dis une connerie mon pauvre... Avec cette méthode pour l'envoi d'un fichier de 1 Mo (timer à 1 Ms + trames à 6 Ko, en comptant aussi la mise en mémoire du fichier et la reconstruction du fichier...), ça prend qq secondes à être transféré...

*** le coup du timer de 1ms et su sleep de 1ms aussi je trouve que c'est un peu au petit bonheur la chance :

Notre pb est le suivant : si on envoit plusieurs trames au meme socket, sur de l'execution machine, les trames se concatènent. Normal, puisque un processeur de 1 GHz par exemple, exécute 1 MIPS (million d'instructions "machine" par seconde), ce qui équivaudrait (au pif) à un timer à 1/100000 seconde... Nous, on utilise pour résoudre ce pb, un timer à 1/1000 seconde, c qui passe super largement... Décidément, t'as rien testé avant de dire toutes tes âneries...


Alors la prochaine fois avant de te lancer dans un commentaire non constructif et avant de critiquer tout le monde, tu ferais mieux de faire des tests. Je ne supportent absolument pas les mecs qui critiquent alors qu'ils n'y comprennent pas grand choses eux mêmes, voire rien du tout dans ton cas. Moi, avant de mettre mon commentaire sur cette source, j'ai suivi des cours sur les winsocks, j'ai fait une bataille navalle en réseau, un chat poste à poste et une appli (client et serveur) qui simule le principe d'un ftp avec transfert de fichiers sur un réseau.
A bon attendeur...
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
14 août 2003 à 18:50
salut à tous
g regardé tout les posts et aucun ne me parait béton de chez béton pour eviter le mélange :
-les doevents ça marche un peu qd ça veut

-le coup du timer de 1ms et su sleep de 1ms aussi je trouve que c'est un peu au petit bonheur la chance genre peut etre que la trame aura le temps d'etre envoyée avant de se faire concatenée avec une autre, meme si le sleep de 1 est censé marcher. en plus si tu as besoin d'envoyer plusieurs packet rapidement tu perd 1ms par envoie au final ç peut faire beaucoup surtout si tu bosse en local

- la technique de Greengold pour les entetes de trame, ça bouffe de la bande passante et en plus tu sais jamais exactement à partir de combien la trame va etre découpé (winsock c'est parait-il 10 ko mais ça peut changer) donc tu peut pas choisir toi meme de la decouper à telle taille.

nan, moi je resterais sur la technique du split, mais j'ai pensé à une amélioration qui la blinderais :
le pb avec le split que par exemple si un chateur tappe ton caractère de fin et envoie le message, ton serveur va pas capter à koi correspont ce que le mec aura taper apres.... d'ou mon idée : mettre des caractères pour inhiber le ou les caractères de fin ;)

exemple :
caractère de fin : ;
inhibeur :

message = "salut moi je parle ds le chat; c'est bien "
message inhib(message)
> message est alors : "salut moi je parle ds le chat; c'est bien "
senddata "CHAT:" & message & ";"

ca vous parait comment ?
docteurre Messages postés 9 Date d'inscription vendredi 8 août 2003 Statut Membre Dernière intervention 24 septembre 2003
14 août 2003 à 18:47
salut à tous
g regardé tout les posts et aucun ne me parait béton de chez béton pour eviter le mélange :
-les doevents ça marche un peu qd ça veut

-le coup du timer de 1ms et su sleep de 1ms aussi je trouve que c'est un peu au petit bonheur la chance genre peut etre que la trame aura le temps d'etre envoyée avant de se faire concatenée avec une autre, meme si le sleep de 1 est censé marcher. en plus si tu as besoin d'envoyer plusieurs packet rapidement tu perd 1ms par envoie au final ç peut faire beaucoup surtout si tu bosse en local

- la technique de Greengold pour les entetes de trame, ça bouffe de la bande passante et en plus tu sais jamais exactement à partir de combien la trame va etre découpé (winsock c'est parait-il 10 ko mais ça peut changer) donc tu peut pas choisir toi meme de la decouper à telle taille.

nan, moi je resterais sur la technique du split, mais j'ai pensé à une amélioration qui la blinderais :
le pb avec le split que par exemple si un chateur tappe ton caractère de fin et envoie le message, ton serveur va pas capter à koi correspont ce que le mec aura taper apres.... d'ou mon idée : mettre des caractères pour inhiber le ou les caractères de fin ;)

exemple :
caractère de fin : ;
inhibeur :

message = "salut moi je parle ds le chat; c'est bien "
message inhib(message)
> message est alors : "salut moi je parle ds le chat; c'est bien "
senddata "CHAT:" & message & ";"

ca vous parait comment ?
Greengold Messages postés 57 Date d'inscription mercredi 16 octobre 2002 Statut Membre Dernière intervention 31 mars 2004
6 août 2003 à 13:59
Moi j'utilise la technique des entêtes de trames.
Par exemple, dans chacune de mes trames, les 3 premiers caractères sont un code que je récupère pour savoir de quel type de trame il s'agit.
Exemple : je veux envoyer un long message. Pour l'occasion ce sera : "0123456789". Disons que je limite la quantité de données envoyés à 4 octets (ou caractères).
"dtm0123" -> début transfert message
"stm4567" -> suite transfert message
"stm89" -> suite transfert message
"ftm" -> fin transfert message

Cette technique n'est valable que si l'on a un paramètre à faire passer. Pour plusieurs paramètres, disons que je veuille envoyer les préférences de mise en forme d'écriture de message d'un client. Je me fixe les règles suivantes : mon entête de trame sera "pmf", mon délimiteur (ou séparteur) de paramètres sera "|", mon 1er param sera la couleur de la police, mon 2eme param sera la taille de la police, mon 3eme param sera la font utilisée...

"pmf|bleu|14|arial"

Ensuite, le truc classique est de faire un selon (les 3 premiers caractères du winsock.getData) dans le dataArrival. Vive le Split... :)
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
6 août 2003 à 13:31
Au début de mon "commentaire" précédent vous pouvez remplacer "serveur" par "côté reception" ;-) Je pense que ca avait besoin d'être clarifier car en fin de compte client et serveur sont des notions relativement abstraites puisque les deux côtés envoient et recoivent des données...
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
6 août 2003 à 13:18
Oui comme d'hab' lol :p
De plus je tiens à dire que c'est côté serveur que vous devez "refaire les messages", en effet si votre message est plus long que la fenêtre autorisée (paramètrable dans le registre sous windows (et accessoirement un autre parametre peut encore la diminuer dans le winsock)) il sera découpé... donc ton système ne permet pas de récuperer un message directement "correcte"
Voilà comment je fais: Dans mes messages je sépare chaque "paramètre" par un caractère (genre ¶) ce qui peut me donner par exemple:
say¶Benj¶Ce que je dis¶
(il faut mettre un ¶ à la fin pour le split ;)) puis à la toute fin du message je rajoute un autre caractère un spécial genre ¢ ce qui me donne au final pour mon message:
say¶Benj¶Ce que je dis¶¢

Bien, donc ca c'est pour l'envois, maintenant à la reception imaginons (même si c'est très peu probable à moins d'avoir une fenêtre ridiculement petite) que le message soit découpé ainsi:
say
¶Be
nj¶
Ce_
que
je_
dis
¶¢

Vous remarquerez qu'à chaque fois il envoit 3 caractères (c'est pour l'exemple hein :) comme vous l'aurez compris ce n'est pas une constante) J'ai matérialisé les espaces par des _ Et remarquez aussi que le dernier packet n'est composé que de deux caractères.
Alors la technique c'est qu'à chaque fois que je receptionne un packet je l'ajoute à une string.Ensuite on fait un split sur cette chaine avec le caractère de fin de message (¢ dans notre exemple) si le ubound est egal à 0 c'est qu'on a pas encore de message complet s'il est egal à 1 (ou plus) c'est bon, on a notre message. Ne reste plus qu'à l'analyser, pour ça je vous fait confiance quand même,mais surtout à le retirer de la chaine ce qui ne devrait pas vous poser de problème non plus, et puis réiterer le test à partir du split pour vérifier qu'on a pas un deuxième message (ce qui évite en plus de s'embarrasser avec la méthode que tu as donnée).

Voilà voilà j'espère que vous avez tout compris, sinon si vous voulez une p'tite source en VB6 ou .NET pas de problème :)
cs_LosAmigos Messages postés 13 Date d'inscription lundi 5 novembre 2001 Statut Membre Dernière intervention 9 octobre 2006
6 août 2003 à 12:22
merci benj, tu as tout a fait raison ;)
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
6 août 2003 à 10:46
Non, tu as raison, j'ai confondu car j'ai trouvé aussi ce problème lorsque j'ai fait un chat entre 2 personne !
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
6 août 2003 à 10:17
neria, concernant ton dernier message c'est impossible ! Tu as en effet forcement un socket par utilisateur, or chaque socket ayant son propre tunnel (ou flux) vers l'ordinateur client les packets ne peuvent pas se mélanger entre deux clients... (suis-je clair ? ^^)
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
6 août 2003 à 08:38
Pour LosAmigos, ta technique est bonne, mais c'est embêtant quand tu fait un chat multiuser et qu'un utilisateur recoit une commande qui ne lui est pas destiné dans le paquet !!!, sinon ça fonction pour un chat simple !
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
6 août 2003 à 08:36
Au lieu de mettre un Timer, essais de le faire attendre 1ms avec l'API sleep :

Declare Sub Sleep Lib "kernel32" ( ByVal dwMilliseconds As Long)
cs_LosAmigos Messages postés 13 Date d'inscription lundi 5 novembre 2001 Statut Membre Dernière intervention 9 octobre 2006
6 août 2003 à 08:26
Moi, j'ai rajouté un caractère de fin qui me permet de séparer les paquets reçu
et donc, lors du getdata, je decoupe .
gabchampagne Messages postés 216 Date d'inscription mercredi 2 avril 2003 Statut Membre Dernière intervention 5 mai 2004
5 août 2003 à 14:58
oui. c quand tu veux faire un programme de chat et que les paquets risque de "fusioné".
Benj1105 Messages postés 103 Date d'inscription samedi 23 mars 2002 Statut Membre Dernière intervention 2 mars 2004
5 août 2003 à 14:38
En fait si j'ai bien compris ce que tu veux éviter c'est que plusieurs paquets soit envoyés comme n'étant qu'un seul ? (en une seule trame au lieu de trames séparées ?)
Greengold Messages postés 57 Date d'inscription mercredi 16 octobre 2002 Statut Membre Dernière intervention 31 mars 2004
5 août 2003 à 12:03
salut,
un message pour neria : ta solution ne marche pas tout le temps.

Si tu fais ce code par exemple :
For i = 1 to 10
DoEvents
winsock.sendData i
DoEvents
Next i

Tu n'enveras pas 10 trames de 1 caractère mais une trame de 10 caractères.
En fait le DoEvents est inopérant dans ce cas là parce que windows reprend la main sur ce code pour l'optimiser.
Il ne faut pas faire de boucle ! Malgré le DoEvents l'exécution machine de ce code est trop rapide, c'est pourquoi je passe par un timer à 1 Ms.
THXTHECATZ Messages postés 2 Date d'inscription mercredi 14 mai 2003 Statut Membre Dernière intervention 5 août 2003
5 août 2003 à 10:57
Personellement, je déclare un Boolean public, qui passe a true lorque l'évenement Winsock_SendComplete() est déclenché, et dans ma procédure d'envoi, je place un:

Do while not LeBooleanEnQuestion

DoEvents

Loop

Ce qui me permet d'être sûr à 100% que le paquet est envoyé avant de transmettre le suivant.

Voila c'est tout :)
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
5 août 2003 à 08:46
Salut Gab !
Je pense que j'ai trouvé une solution autant efficace et moins longue et contraignante que celle là :
Winsock.senddata data 'Envoie le paquet
DoEvents 'Attent que winsocke ait envoyé son paquet pour continuer
Voilà, chez moi ça fonctionne très bien !
@+
Rejoignez-nous