C# Mauvais ID de Paquet

Inscrit
19 Mai 2013
Messages
68
Reactions
0
#1
Salut à tous ! :D

Je reviens une fois de plus pour un problème au niveau de la lecture du Header des paquets...

Voici le code :

Code:
        private void ParseBuffer(byte[] buffer_To_Parse)
        {
            int header;
            int message_ID;
            int length_Count;
            int length;
            byte[] packet_Content = new byte[0];

            using (BigEndianReader big_Endian_Reader = new BigEndianReader(buffer_To_Parse))
            {
                while (big_Endian_Reader.bytes_Avaibles >= 2)
                {
                    header = big_Endian_Reader.ReadShort();

                    message_ID = header >> 2;
                    length_Count = header & 0x3;

                    if (big_Endian_Reader.bytes_Avaibles >= length_Count)
                    {
                        if ((length_Count < 0) || (length_Count > 3))
                        {
                            throw new Exception("Malformated Message Header, invalid bytes number to read message length (inferior to 0 or superior to 3)");
                        }
                        else
                        {
                            length = 0;

                            for (int i = length_Count - 1; i >= 0; i--)
                            {
                                length |= big_Endian_Reader.ReadByte() << (i * 8);
                            }

                            if (length == 0)
                            {
                                packet_Content = new byte[0];
                            }

                            if (big_Endian_Reader.bytes_Avaibles >= length)
                            {
                                packet_Content = big_Endian_Reader.ReadBytes(length);
                            }
                            else if (big_Endian_Reader.bytes_Avaibles < length)
                            {
                                packet_Content = big_Endian_Reader.ReadBytes((int)big_Endian_Reader.bytes_Avaibles);
                            }

                            TreatPacket(message_ID, packet_Content);
                        }
                    }
                }
            }
        }

Et dans ma RichTextBox, je me retrouve avec ça :

[10:52:54] La connexion au serveur d'identification est établie.
[10:52:55] Paquet reçu, ID : 1
[10:52:56] Paquet reçu, ID : 3
[10:52:57] Paquet reçu, ID : 10
[10:52:57] File d'attente : 15/15.
[10:52:57] Paquet reçu, ID : 6314
[10:52:57] Paquet reçu, ID : 10
[10:52:57] File d'attente : 0/10.
[10:52:57] Paquet reçu, ID : 22
[10:52:57] Connexion réussie.
[10:52:57] Paquet reçu, ID : 6469
[10:52:57] La connexion au serveur de jeu est établie.
[10:52:57] Paquet reçu, ID : 1
[10:52:57] Paquet reçu, ID : 101
[10:52:57] Paquet reçu, ID : 6362
[10:52:57] Paquet reçu, ID : 111
[10:52:57] Paquet reçu, ID : 175
[10:52:57] Paquet reçu, ID : 6340
[10:52:57] Paquet reçu, ID : 6305
[10:52:57] Paquet reçu, ID : 6434
[10:52:57] Paquet reçu, ID : 6216
[10:52:57] Paquet reçu, ID : 6267
[10:52:57] Paquet reçu, ID : 176
[10:52:57] Paquet reçu, ID : 6362
[10:52:58] Paquet reçu, ID : 6100
[10:52:58] File d'attente : 1/1.
[10:52:58] Paquet reçu, ID : 6100
[10:52:58] File d'attente : 0/0.
[10:52:58] Paquet reçu, ID : 176
[10:52:58] Paquet reçu, ID : 6100
[10:52:58] File d'attente : 0/0.
[10:52:58] Paquet reçu, ID : 151
[10:52:58] Paquet reçu, ID : 6362
[10:52:58] Paquet reçu, ID : 176
[10:52:58] Paquet reçu, ID : 6100
[10:52:58] File d'attente : 0/0.
[10:52:58] Paquet reçu, ID : 6087
[10:52:58] Paquet reçu, ID : 153
[10:52:58] Paquet reçu, ID : 272
[10:52:58] Connecté en tant que :
[10:52:58] Paquet reçu, ID : -2368
[10:52:58] Paquet reçu, ID : 3016
[10:52:58] Paquet reçu, ID : -1939
[10:52:58] Paquet reçu, ID : 3264
[10:52:58] Paquet reçu, ID : 512
[10:52:58] Paquet reçu, ID : 0
[10:52:58] Paquet reçu, ID : 128
[10:52:58] Paquet reçu, ID : 7134
[10:52:58] Paquet reçu, ID : 54
[10:52:58] Paquet reçu, ID : 1152
[10:52:58] Paquet reçu, ID : 7067
[10:52:58] Inventaire chargé.
[10:52:58] Paquet reçu, ID : 6231
[10:52:58] Paquet reçu, ID : 6231
[10:52:58] Paquet reçu, ID : 5689
[10:52:58] Paquet reçu, ID : 6058
[10:52:58] Paquet reçu, ID : 6440
Si quelqu'un a une petite idée ? :D

Veriditas.
 
Inscrit
3 Février 2012
Messages
13
Reactions
0
#2
Ton header est dans ton while, il va donc changer à chaque itération.
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#3
Cue a dit:
Ton header est dans ton while, il va donc changer à chaque itération.
C'est normal qu'il soit dans le while. Il faut qu'il lise tant que le nombre de bytes disponibles est supérieur à 2 (soit un header). En le sortant de la boucle, ça ne marche pas du tout du moins... :S
 
Inscrit
3 Février 2012
Messages
13
Reactions
0
#4
Un Short c'est déjà sur 2 bytes (Int16)
Je suis pas un pro dans le domaine, mais je pense que ça vient de là.

Imagine que ton packet fait 30 bytes.

Ben il va remplacer ta variable header à chaque fois
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#5
Non, parce que dans TreatPacket, il lit le contenu. Mais effectivement, je pense que ça vient de là ! Quand il y a un seul message dans le packet, ça fonctionne, mais quand il y en a plusieurs au lieur de lire les bytes (2 (pour le premier header) + longueur du premier paquet + 1) et (2 (pour le premier header) + longueur du premier paquet + 2) pour le second header, il lira les bytes 3 et 4. Du moins c'est ce que je pense comprendre

EDIT : Non en fait j'ai dit n'importe quoi. Je pousse bien le BigEndianReader.bytesAvaible jusqu'à la fin du paquet.
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#6
c'est parceque le dernier message du paquet precedent l'erreur etait pas complet avant l'erreur du genre :
[paquet 1 = message xxx (ou pas) + message 272 de longueur 32] (32 ca vien de mon imagination) mais dans le paquet reste que 28 bytes a lire (pareil 28 ca vient de mon imagination)
[paquet 2 = 4 bytes restants a lire du message 272 + message yyy (ou pas)] pas de header dans ces 4 bytes comme c'est la suite du message 272

donc le paquet de l'erreur , paquet 2 , commence pas par un header mais par la fin du dernier message ce qui donne n'importe quoi comme ID comme c'en est pas un

il ne faut pas traiter 272 (ou peu importe l'id d'ailleur) si sa taille est pas complete , sauvegarder les bytes restants a traiter dans un 2ieme buffer temporaire (y compris le header) , quand le 2ieme paquet arrive regarder si y'a un 2ieme buffer , si oui prendre ce 2ieme buffer et ajouter a sa suite le 2ieme paquet comme ca le buffer final commence bien par un header (celui du message 272 et que le message 272 a pas encore ete traité comme il etait incomplet)

tu tests : if (big_Endian_Reader.bytes_Avaibles >= length_Count) , avec le ">" pour les cas ou y'a plusieurs messages dans le paquet
mais faut aussi tester : if (big_Endian_Reader.bytes_Avaibles < length_Count) avec le "<" pour les cas ou le dernier message est incomplet alors faut sauvegarder dans un 2ieme buffer
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#7
ToOnS a dit:
c'est parceque le dernier message du paquet precedent l'erreur etait pas complet avant l'erreur du genre :
[paquet 1 = message xxx (ou pas) + message 272 de longueur 32] (32 ca vien de mon imagination) mais dans le paquet reste que 28 bytes a lire (pareil 28 ca vient de mon imagination)
[paquet 2 = 4 bytes restants a lire du message 272 + message yyy (ou pas)] pas de header dans ces 4 bytes comme c'est la suite du message 272

donc le paquet de l'erreur , paquet 2 , commence pas par un header mais par la fin du dernier message ce qui donne n'importe quoi comme ID comme c'en est pas un

il ne faut pas traiter 272 (ou peu importe l'id d'ailleur) si sa taille est pas complete , sauvegarder les bytes restants a traiter dans un 2ieme buffer temporaire (y compris le header) , quand le 2ieme paquet arrive regarder si y'a un 2ieme buffer , si oui prendre ce 2ieme buffer et ajouter a sa suite le 2ieme paquet comme ca le buffer final commence bien par un header (celui du message 272 et que le message 272 a pas encore ete traité comme il etait incomplet)

tu tests : if (big_Endian_Reader.bytes_Avaibles >= length_Count) , avec le ">" pour les cas ou y'a plusieurs messages dans le paquet
mais faut aussi tester : if (big_Endian_Reader.bytes_Avaibles < length_Count) avec le "<" pour les cas ou le dernier message est incomplet alors faut sauvegarder dans un 2ieme buffer
Merci beaucoup ! J'essaie de régler ça demain aprèm si j'ai le temps. :)

EDIT :

C'est bon, tout marche impec, merci ToOns ! Donc voilà le code :

Code:
        private byte[] _buffer = new byte[0];
        private int _header = 0;
        private int _message_ID = 0;
        private int _length_Count = 0;
        private int _length = 0;
        private byte[] _packet_Content = new byte[0];

        private void ParseBuffer(byte[] buffer_To_Parse)
        {
            // Timer en cas de blocage sur un paquet
            _dispatcher_Timer_Disconnect.Interval = new TimeSpan(0, 1, 0);
            _dispatcher_Timer_Disconnect.Start();

            using (BigEndianReader big_Endian_Reader = new BigEndianReader(buffer_To_Parse))
            {
                // Aucun morceau de paquet lu précédemment
                if (_buffer.Length == 0)
                {
                    // Lit lorsque qu'il y a un header
                    while (big_Endian_Reader.bytes_Avaibles >= 2)
                    {
                        _header = big_Endian_Reader.ReadShort();

                        // Récupération du message et du type de longueur
                        _message_ID = _header >> 2;
                        _length_Count = _header & 0x3;

                        // Lit lorsqu'il y a la longueur
                        if (big_Endian_Reader.bytes_Avaibles >= _length_Count)
                        {
                            if ((_length_Count < 0) || (_length_Count > 3))
                            {
                                throw new Exception("Malformated Message Header, invalid bytes number to read message length (inferior to 0 or superior to 3)");
                            }
                            else
                            {
                                // Récupère la longueur
                                _length = 0;

                                for (int i = _length_Count - 1; i >= 0; i--)
                                {
                                    _length |= big_Endian_Reader.ReadByte() << (i * 8);
                                }

                                if (_length == 0)
                                {
                                    _packet_Content = new byte[0];
                                }

                                // Paquet contenu entièrement dans ce tampon
                                if (big_Endian_Reader.bytes_Avaibles >= _length)
                                {
                                    // Récupère le contenu du paquet
                                    _packet_Content = big_Endian_Reader.ReadBytes(_length);

                                    // Traite le paquet
                                    TreatPacket(_message_ID, _packet_Content);
                                }
                                // Morceau de paquet dans le tampon suivant
                                else if (big_Endian_Reader.bytes_Avaibles < _length)
                                {
                                    // Récupère le paquet dans un tampon pour être traité plus tard
                                    _buffer = big_Endian_Reader.ReadBytes((int)big_Endian_Reader.bytes_Avaibles);
                                }
                            }
                        }
                    }
                }
                // Un paquet a déjà été lu
                else
                {
                    // Paquet contenu entièrement dans ce tampon
                    if (big_Endian_Reader.bytes_Avaibles >= _length)
                    {
                        // Récupère le contenu du tampon précédent
                        _packet_Content = _buffer;
                        _buffer = new byte[0];

                        // Récupère le contenu dans le tampon suivant
                        _packet_Content = big_Endian_Reader.ReadBytes(_length);

                        // Traite le paquet
                        TreatPacket(_message_ID, _packet_Content);
                    }
                    // Morceau de paquet dans le tampon suivant
                    else if (big_Endian_Reader.bytes_Avaibles < _length)
                    {
                        // Récupère le paquet dans un tampon pour être traité plus tard
                        _buffer = big_Endian_Reader.ReadBytes((int)big_Endian_Reader.bytes_Avaibles);
                    }
                }
            }
        }
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#8
UP !

Mon dernier code ne marche toujours pas :

[18:56:18] Paquet reçu : 6231
[18:56:18] Paquet reçu : 6231
[18:56:18] Paquet reçu : 5689
[18:56:18] Paquet reçu : 6058
[18:56:24] Paquet reçu : 3072
[18:56:24] Paquet reçu : 2112
[18:56:24] Paquet reçu : -6976
[18:56:24] Paquet reçu : 0
[18:56:24] Paquet reçu : 7321
[18:56:24] Paquet reçu : 960
Et c'est jamais pareil :

[18:58:32] Paquet reçu : 6231
[18:58:32] Paquet reçu : 6231
[18:58:32] Paquet reçu : 5689
[18:58:32] Paquet reçu : 6058
[18:58:32] Paquet reçu : 6720
[18:58:32] Paquet reçu : 401
[18:58:32] Paquet reçu : -5440
[18:58:32] Paquet reçu : -6258
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#9
en basic ca donne ca ("packet" ca veut dire en fait "message" :oops: , le vrai paquet est dans data() ) :
Code:
    Dim Data_Out(0) As Byte ' au cas ou le buffer est trop petit pour la reception (debut du paquet recu trop long)
    Dim Waiting As Integer ' au cas ou le buffer est trop petit pour la reception

    Public Sub parsing(ByVal data() As Byte)
        Try
            Dim index As Integer ' pour savoir ou on est
            Dim id_and_length As UShort ' les 2 premiers octets (16 bits)
            Dim packet_id As UShort ' les 14 premiers bits des 16
            Dim packet_length_of As Byte ' les 2 derniers bits des 16
            Dim packet_length As Integer ' la longueur du packet
            Dim Packet_Start As Integer
            Dim Packet_End As Integer

            If Waiting > 1 Then ' le buffer etait trop petit ?
                Dim data_temps(data.Length + Data_Out.Length - 1) As Byte ' on créé un tableau de byte temporaire
                Array.Copy(Data_Out, 0, data_temps, 0, Data_Out.Length) ' on met le debut du paquet trop long dans le tableau temporaire
                Array.Copy(data, 0, data_temps, Data_Out.Length, data.Length) ' on met la reception a la suite
                data = data_temps ' on met le tableau temporaire dans le tableau de travail
            End If

            Do Until index = data.Length ' on traite jusque la fin
                Packet_Start = index
                id_and_length = data(index) * 256 + data(index + 1) ' les 2 premiers octets
                packet_length_of = id_and_length And 3 ' on veut les 2 derniers bits donc on masque (and) avec 11 en binaire (3 en decimal)
                packet_id = id_and_length >> 2 ' on veut les 14 premiers bits donc on decale les 16 bits de 2 bits vers la droite
                index += 2 + packet_length_of  ' on avance des 2 octets de id_and_length + du nombre d'octets de la taille de taille

                Select Case packet_length_of ' on lit le bon nombre d'octet pour connaitre la taille des données
                    Case 0
                        packet_length = 0
                    Case 1
                        packet_length = data(index - 1)
                    Case 2
                        packet_length = 256 * data(index - 2) + data(index - 1)
                    Case 3
                        packet_length = 65536 * data(index - 3) + 256 * data(index - 2) + data(index - 1)
                End Select

                If index + packet_length > data.Length Then ' buffer trop petit ?
                    Waiting = packet_length + index - Packet_Start ' alors on le signale
                    ReDim Data_Out(data.Length - Packet_Start - 1) ' on redimensionne le tableau de debut du paquet trop long
                    Array.Copy(data, Packet_Start, Data_Out, 0, data.Length - Packet_Start) ' on copie le debut du paquet trop long
                    Exit Sub ' on sort
                End If

                Log.Invoke(loger, "recu : id = " & packet_id & ", taille = " & packet_length) ' on ecrit l'ID et la taille
                Dim packet(0) As Byte ' on prepare le paquet
                If packet_length > 0 Then ' si sa taille est plus grande que 0 on redimensionne
                    ReDim packet(packet_length - 1)
                    Array.Copy(data, index, packet, 0, packet_length) ' et on copie les donnée
                End If
                ' ---> traitement du message : 
                DataCheck(packet_id, New Dofus.DofusReader(New IO.MemoryStream(packet))) ' on verra plus tard
                index += packet_length ' on met l'index a jour
                Packet_End = index
                If Packet_End = data.Length Then ' si ca tombe pile poil alors le buffer etait assez grand
                    Waiting = 0 ' on reset
                    ReDim Data_Out(0) ' on reset
                End If
            Loop

        Catch e As Exception
            Console.WriteLine("parsing() " & e.TargetSite.Name & " -> " & e.Message)
        End Try
    End Sub
Data_Out et Waiting ne doivent pas etre "reset" a l'appelle de la fonction , les mettre en "public shared" si ils sont ailleurs que dans la classe de reception
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#10
ToOnS a dit:
en basic ca donne ca ("packet" ca veut dire en fait "message" :oops: , le vrai paquet est dans data() ) :
Code:
    Dim Data_Out(0) As Byte ' au cas ou le buffer est trop petit pour la reception (debut du paquet recu trop long)
    Dim Waiting As Integer ' au cas ou le buffer est trop petit pour la reception

    Public Sub parsing(ByVal data() As Byte)
        Try
            Dim index As Integer ' pour savoir ou on est
            Dim id_and_length As UShort ' les 2 premiers octets (16 bits)
            Dim packet_id As UShort ' les 14 premiers bits des 16
            Dim packet_length_of As Byte ' les 2 derniers bits des 16
            Dim packet_length As Integer ' la longueur du packet
            Dim Packet_Start As Integer
            Dim Packet_End As Integer

            If Waiting > 1 Then ' le buffer etait trop petit ?
                Dim data_temps(data.Length + Data_Out.Length - 1) As Byte ' on créé un tableau de byte temporaire
                Array.Copy(Data_Out, 0, data_temps, 0, Data_Out.Length) ' on met le debut du paquet trop long dans le tableau temporaire
                Array.Copy(data, 0, data_temps, Data_Out.Length, data.Length) ' on met la reception a la suite
                data = data_temps ' on met le tableau temporaire dans le tableau de travail
            End If

            Do Until index = data.Length ' on traite jusque la fin
                Packet_Start = index
                id_and_length = data(index) * 256 + data(index + 1) ' les 2 premiers octets
                packet_length_of = id_and_length And 3 ' on veut les 2 derniers bits donc on masque (and) avec 11 en binaire (3 en decimal)
                packet_id = id_and_length >> 2 ' on veut les 14 premiers bits donc on decale les 16 bits de 2 bits vers la droite
                index += 2 + packet_length_of  ' on avance des 2 octets de id_and_length + du nombre d'octets de la taille de taille

                Select Case packet_length_of ' on lit le bon nombre d'octet pour connaitre la taille des données
                    Case 0
                        packet_length = 0
                    Case 1
                        packet_length = data(index - 1)
                    Case 2
                        packet_length = 256 * data(index - 2) + data(index - 1)
                    Case 3
                        packet_length = 65536 * data(index - 3) + 256 * data(index - 2) + data(index - 1)
                End Select

                If index + packet_length > data.Length Then ' buffer trop petit ?
                    Waiting = packet_length + index - Packet_Start ' alors on le signale
                    ReDim Data_Out(data.Length - Packet_Start - 1) ' on redimensionne le tableau de debut du paquet trop long
                    Array.Copy(data, Packet_Start, Data_Out, 0, data.Length - Packet_Start) ' on copie le debut du paquet trop long
                    Exit Sub ' on sort
                End If

                Log.Invoke(loger, "recu : id = " & packet_id & ", taille = " & packet_length) ' on ecrit l'ID et la taille
                Dim packet(0) As Byte ' on prepare le paquet
                If packet_length > 0 Then ' si sa taille est plus grande que 0 on redimensionne
                    ReDim packet(packet_length - 1)
                    Array.Copy(data, index, packet, 0, packet_length) ' et on copie les donnée
                End If
                ' ---> traitement du message : 
                DataCheck(packet_id, New Dofus.DofusReader(New IO.MemoryStream(packet))) ' on verra plus tard
                index += packet_length ' on met l'index a jour
                Packet_End = index
                If Packet_End = data.Length Then ' si ca tombe pile poil alors le buffer etait assez grand
                    Waiting = 0 ' on reset
                    ReDim Data_Out(0) ' on reset
                End If
            Loop

        Catch e As Exception
            Console.WriteLine("parsing() " & e.TargetSite.Name & " -> " & e.Message)
        End Try
    End Sub
Data_Out et Waiting ne doivent pas etre "reset" a l'appelle de la fonction , les mettre en "public shared" si ils sont ailleurs que dans la classe de reception
Merci, je regarde ça ce soir ! :)
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#11
UP :

Je sais d'où vient le problème ! Il arrive que deux messages arrivent à des intervalles très rapprochés et donc le traitement du paquet est exécuté 2 fois en même temps, et ça devient alors le bordel dans la lecture. Mais comment résoudre ce problème ? Comment puis-je bloquer l'accès au code qui parse les messages, tant que ce dernier n'a pas fini de parser le dernier buffer reçu ?

Pour mieux comprendre de quoi je parle :

http://puu.sh/5C86p.jpg
J'appuie sur F10 :
http://puu.sh/5C87M.jpg
J'appuie sur F10 :
http://puu.sh/5C89a.jpg
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#12
faudrait voire comment tu appelles la fonction de parsing , en l'appelant comme ca : (ca c'est le thread qui recoit , donc une boucle et pas un evenement)
Code:
 Sub Ecoute_Connexion()
        While _socket_Connexion.Connected ' boucle infinie tant que connecté
            Dim i = _socket_Connexion.Receive(buffer) ' on met dans i le nombre d'octets recu
            Dim data(i - 1) As Byte ' on créé un tableau de bytes du nombre de bytes recus
            Array.Copy(buffer, data, i) ' on copie buffer dans data
            parsing(data) ' on lance le parsing ' =====> tant que ca c'est pas fini il attend avant de revenir a Dim i = _socket_Connexion.Receive(buffer)
        End While
    End Sub
j'imagine que tu ne fais comme ca et que tu le fais plus proprement avec un evenement quand tu recois quelquechose , du coup il les balance en parallele , dans ce cas il faudrait faire un FIFO (une queue , http://msdn.microsoft.com/fr-fr/library ... 10%29.aspx , quand tu recois quelquechose dans l'evenement tu .Enqueue et quand tu le parse tu le .Dequeue jusque la queue soit vide)

ou alors
(mais ca c'est pas certain que ca marche si plusieurs receptions attendent en meme temps je ne sais si ca sera bien la premiere a avoir commencé a attendre qui passera en 1ere) mettre une variable Working (un boolean ca suffit, declaré comme Waiting, au meme endroit et en "public shared" si la fonction est ailleur que dans la classe de reception) a "True" apres
Code:
  Public Sub parsing(ByVal data() As Byte)
        Try
====> Working = True
et a False apres le loop
Code:
                If Packet_End = data.Length Then ' si ca tombe pile poil alors le buffer etait assez grand
                    Waiting = 0 ' on reset
                    ReDim Data_Out(0) ' on reset
                End If
            Loop
====> working = False
et dans l'evenement de reception attendre tant que Waiting est negatif avec un truc du genre
Code:
# ton evenement de reception
reception=blablabla
Do until Working = True
      Application.DoEvents() 'ca c'est pour pas que la boucle prenne tout l'espace CPU a rien faire , si on met rien alors la boucle prendrait un coeur de CPU juste pour attendre
loop
parsing(ton_buffer)
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#13
Concrètement, voici mon code (Le parsing est une vulgaire traduction en C# de ton code) :

Code:
    class SocketManager
    {
        // variables...
        private Thread _reception_Thread;
        private byte[] _packet_Out;
        private int _bytes_Wanted;
        // variables...

        public void Connect(ConnectionInformations connection_Informations)
        {
                        // code...
                        // Quand la connexion est réussie
                        _reception_Thread = new Thread(new ThreadStart(SocketReception));
                        _reception_Thread.Start();
                        // code...
        }

        private void SocketReception()
        {
            // Réception des données en boucle infinie durant la période connectée
            while ((_socket != null) && (_socket.Connected))
            {
                // Buffer/tampon dynamique
                byte[] buffer = new byte[_socket.Available];

                if (buffer.Length != 0)
                {
                    _socket.Receive(buffer);
                    ParseBuffer(buffer); // Conversion du buffer
                }
            }
        }

        private void ParseBuffer(byte[] packet_In)
        {
            int index = 0;
            ushort header;
            ushort packet_ID = 0;
            byte packet_Length_Type = 0;
            int packet_Length = 0;
            int packet_Start = 0;
            int packet_End;
            byte[] packet_Temporary;

            _timer_Reception_Thread = new System.Threading.Timer(TimerReceptionThreadFinished, null, 60000, 250);

            if (_bytes_Wanted > 1) // Le buffer précédent ne contenait pas tout le message
            {
                packet_Temporary = new byte[packet_In.Length + _packet_Out.Length - 1]; // Création du message temporaire
                Array.Copy(_packet_Out, 0, packet_Temporary, 0, _packet_Out.Length); // Copie de début du message dans le message temporaire
                Array.Copy(packet_In, 0, packet_Temporary, _packet_Out.Length, packet_In.Length); // Copie du buffer suivant dans le message temporaire
                packet_In = packet_Temporary;
            }

            while (index < packet_In.Length) // Tant qu'il y a quelque chose à lire dans le buffer
            {
                packet_Start = index;
                header = (ushort)(packet_In[index] * 256 + packet_In[index + 1]); // Récupération de l'header
                packet_Length_Type = (byte)(header & 3); // Récupération du type de longueur de message
                packet_ID = (ushort)(header >> 2); // Récupération de l'ID du message
                index += 2 + packet_Length_Type;

                switch (packet_Length_Type) // Récupération de l'hedaer
                {
                    case 0:
                        packet_Length = 0;
                        break;
                    case 1:
                        packet_Length = packet_In[index - 1];
                        break;
                    case 2:
                        packet_Length = 256 * packet_In[index - 2] + packet_In[index - 1];
                        break;
                    case 3:
                        packet_Length = 65536 * packet_In[index - 3] + 256 * packet_In[index - 2] + packet_In[index - 1];
                        break;
                }

                if (index + packet_Length > packet_In.Length) // Le buffer ne contient pas tout le message
                {
                    _bytes_Wanted = packet_Length + index - packet_Start;
                    _packet_Out = new byte[packet_In.Length - packet_Start - 1];
                    Array.Copy(packet_In, packet_Start, _packet_Out, 0, packet_In.Length - packet_Start); // Copie le début du message dans un buffer
                    return;
                }

                MainForm.actual_MainForm.SetLogsBot("recu : id = " + packet_ID.ToString() + ", taille = " + packet_Length.ToString());

                byte[] final_Packet = new byte[0];

                if (packet_Length > 0)
                {
                    final_Packet = new byte[packet_Length];
                    Array.Copy(packet_In, index, final_Packet, 0, packet_Length); // On copie le message final
                }

                TreatPacket(packet_ID, final_Packet); // Traite le packet

                index += packet_Length;
                packet_End = index;

                if (packet_End == packet_In.Length) // Réinitialisation
                {
                    _bytes_Wanted = 0;
                    _packet_Out = new byte[0];
                }
            }
        }
    }

Normalement, t'as l'essentiel ici !

Le problème intervient quand je reçois le paquet 6440 (PrismsListMessage si je me souviens bien, flemme de chercher dans le code source).

Donc voilà toutes les infos que je peux te donner : http://puu.sh/5D1Yl.jpg

EDIT :

Ce que je trouve super chelou, c'est le paquet_Length de 11258... Donc, je sais pas si à la normale, ce paquet est vraiment super, super, super long, ou non...

EDIT 2 :

J'ai relancé, et je plante toujours après le paquet 6058 de taille 2 (comme toute à l'heure), mais cette fois, le paquet n'est plus le 6440 de longueur 11 258, mais le 6 de longueur 16764928... C'est déprimant !

EDIT 3 :

Je suis allé check le paquet 6058, c'est AligmentRankUpdateMessage et son deserialize ressemble à ça :

Code:
      public function deserializeAs_AlignmentRankUpdateMessage(param1:IDataInput) : void {
         this.alignmentRank = param1.readByte();
         if(this.alignmentRank < 0)
         {
            throw new Error("Forbidden value (" + this.alignmentRank + ") on element of AlignmentRankUpdateMessage.alignmentRank.");
         }
         else
         {
            this.verbose = param1.readBoolean();
            return;
         }
      }

Un byte + un boolean, 2 bytes, la longueur de 2 est bonne. Donc jusqu'à la fin de la lecture de ce paquet, tout est normal !

EDIT 4 :

Bon, il semblerait que j'ai résolu le problème. Dans les statistiques, 1 connexion sur une dizaine présente un décalage dans la lecture, et 1 connexion sur une dizaine bug totalement et le programme crash.

Voici le code ParseBuffer :

Code:
        private void ParseBuffer(byte[] packet_In)
        {
            int index = 0;
            ushort header;
            ushort packet_ID = 0;
            byte packet_Length_Type = 0;
            int packet_Length = 0;
            int packet_Start = 0;
            int packet_End;
            byte[] packet_Temporary;

            _timer_Reception_Thread = new System.Threading.Timer(TimerReceptionThreadFinished, null, 60000, 250);

            if (_bytes_Wanted > 1) // Le buffer précédent ne contenait pas tout le message
            {
                packet_Temporary = new byte[packet_In.Length + _packet_Out.Length]; // Création du message temporaire
                Array.Copy(_packet_Out, 0, packet_Temporary, 0, _packet_Out.Length); // Copie de début du message dans le message temporaire
                Array.Copy(packet_In, 0, packet_Temporary, _packet_Out.Length, packet_In.Length); // Copie du buffer suivant dans le message temporaire
                packet_In = packet_Temporary;
            }

            while (index < packet_In.Length) // Tant qu'il y a quelque chose à lire dans le buffer
            {
                packet_Start = index;
                header = (ushort)(packet_In[index] * 256 + packet_In[index + 1]); // Récupération de l'header
                packet_Length_Type = (byte)(header & 3); // Récupération du type de longueur de message
                packet_ID = (ushort)(header >> 2); // Récupération de l'ID du message
                index += 2 + packet_Length_Type;

                switch (packet_Length_Type) // Récupération de l'hedaer
                {
                    case 0:
                        packet_Length = 0;
                        break;
                    case 1:
                        packet_Length = packet_In[index - 1];
                        break;
                    case 2:
                        packet_Length = 256 * packet_In[index - 2] + packet_In[index - 1];
                        break;
                    case 3:
                        packet_Length = 65536 * packet_In[index - 3] + 256 * packet_In[index - 2] + packet_In[index - 1];
                        break;
                }

                if (index + packet_Length > packet_In.Length) // Le buffer ne contient pas tout le message
                {
                    _bytes_Wanted = packet_Length + index - packet_In.Length;
                    _packet_Out = new byte[packet_In.Length - packet_Start];
                    Array.Copy(packet_In, packet_Start, _packet_Out, 0, packet_In.Length - index); // Copie le début du message dans un buffer
                    return;
                }

                MainForm.actual_MainForm.SetLogsBot("recu : id = " + packet_ID.ToString() + ", taille = " + packet_Length.ToString());

                byte[] final_Packet = new byte[0];

                if (packet_Length > 0)
                {
                    final_Packet = new byte[packet_Length];
                    Array.Copy(packet_In, index, final_Packet, 0, packet_Length); // On copie le message final
                }

                TreatPacket(packet_ID, final_Packet); // Traite le packet

                index += packet_Length;
                packet_End = index;

                if (packet_End == packet_In.Length) // Réinitialisation
                {
                    _bytes_Wanted = 0;
                    _packet_Out = new byte[0];
                }
            }
        }

Ce que j'ai modifié concrètement :
packet_Temporary = new byte[packet_In.Length + _packet_Out.Length] (Suppression du - 1 dans la taille du tableau de bytes)
_bytes_Wanted = packet_Length + index - packet_In.Length;
_packet_Out = new byte[packet_In.Length - packet_Start]
(Remplacement de packet_Start par packet_In.Length // Suppression du - 1 dans la taille du tableau de bytes)

Bon, maintenant le top serait de comprendre les 2 connexion sur une dizaine qui échouent et régler ce problème, sinon mon bot devient inutile !
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#14
ah oui pour les -1 c'est normal , en basic un tableau est compté avec +1 (du coup faut un -1) en C(#) non.

je crois que y'a un probleme pour _bytes_Wanted (qui d'ailleur est pas "octets voulus" mais "octets en trop" , enfin debut de message sans sa fin donc on considere qu'ils sont en trop pour le moment et qu'on traitera ca plus tard avec la prochaine reception) :

tu as :
_bytes_Wanted = packet_Length + index - packet_In.Length; => taille du message + index (donc debut du message reel sans le header) - taille totale du packet
ce qui fait que parfois ca peu etre =< 0 alors qu'en fait c'est > 0 , du coup le passage de data_out dans le buffer de travail ne se fait pas (comme c'est _bytes_Wanted qui declenche ce passage)

ca devrait etre : _bytes_Wanted = packet_In.Length - debut du message pas complet (header compris , donc packet_Start qui est en fait message_start)

si c'est pas ca alors ca se comlique trop , sans connaitre les données au moment ou ca plante je saurais pas t'aider sauf par skype et/ou teamviewer ([email protected] :p , pour connaitre les données donc le "pourquoi du comment" ca plante en se mettant d'accord sur une date/heure car j'oubli toujours d'allumer skype, ah n'en profitez pas pour m'envoyer des pubs de viagra par mail , j'ai deja ce qu'il faut)
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#16
etonnant , il doit y'avoir encore un truc qu'on a pas vu je pense que le mieux serait de voir tout ca en live
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#17
ToOnS a dit:
etonnant , il doit y'avoir encore un truc qu'on a pas vu je pense que le mieux serait de voir tout ca en live
Le plus etonnant, c'est que ça n'arrive pas à chaque fois ! Je dirai même que c'est rare ! Mais iui, l'option du luve, malgré la puissance de mon Pc, me parait une bonne option !
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#18
UP ! Je crois avoir trouvé un problème ! En effet, je pense que j'utilise mal mes threads ! Y a-t-il une façon particulière de lancer des threads lorsqu'un autre thread est déjà lancé ? En effet, je lance un thread A puis un thread B. Un peu plus tard, à un point d'arrêt, je peux remarquer que thread_A.IsAlive = false. Pourtant j'ai nulle part arrêté le thread A ! Enfin soit, j'ai pas trop le temps de développer tout ce que je sais par rapport au problème là, je suis en pleine révisions de bac blanc (et la à partir de demain) en bac blanc, mais j'espère que ça vous donnera déjà quelques idées à me proposer.
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#19
Montre nous le code de tes threads.
 
Inscrit
19 Mai 2013
Messages
68
Reactions
0
#20
lolodu93 a dit:
Montre nous le code de tes threads.
Ok. Alors j'ai 5 threads.

_connection_Thread, _order_Thread, _reception_Thread, _parsing_Thread, _feeding_Thread.

_connection_Thread est lancé lorsque la série de connexion commence (oui, mon bot se connecte toutes les x heures pour nourrir les familiers).

_order_Thread est lancé lorsque l'utilisateur rentre une commande parce que mon programme est sous la forme d'une invite de commande (2 textboxs de logs et une textbox pour taper les commandes).

_reception_Thread est lancé lorsque la connexion socket est établie avec le server.

_parsing_Thread est lancé en même temps que _reception_Thread en gros.

_feeding_Thread est lancé quand le bot nourrit.

Donc l'appel de _order_Thread :

Code:
        private void richTextBoxOrder_Enter(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) // Touche "Enter" saisie
            {
                // Lance le thred de commande
                _order_Thread = new Thread(new ThreadStart(OrderReception));
                _order_Thread.Start();
            }
        }
L'appel de _connection_Thread est fait lorsque la commande "Launch()" est rentrée dans la textbox :

Code:
        public void LauchConnections()
        {
            // Lance le thread de connection
            _connection_Thread = new Thread(new ThreadStart(Connect));
            _connection_Thread.Start();
        }
_reception_Thread :

Code:
        public void Connect(ConnectionInformations connection_Informations)
        {
            if (!_socket.Connected)
            {
                // Prévoit une éventuelle SoscketException
                try
                {
                    // Connexion au serveur
                    _socket.Connect(connection_Informations.address, connection_Informations.port);

                    // Teste si la connexion est établie
                    if (_socket.Connected)
                    {
                        MainForm.actual_MainForm.SetLogsBot("La connexion au serveur " + connection_Informations.server_Name + " est établie.");

                        _reception_Thread = new Thread(new ThreadStart(SocketReception));
                        _reception_Thread.Start();
                    }
                    else
                    {
                        MainForm.actual_MainForm.SetLogsBot("La connexion au serveur " + connection_Informations.server_Name + "a échoué.");
                    }
                }
                catch (SocketException sock_Ex)
                {
                    MainForm.actual_MainForm.SetLogsBot("[Socket Exception] " + sock_Ex.Message);
                }
            }
            else
            {
                // Cas de changement de serveur de connexion
                _socket.Disconnect(false);
                _socket.Dispose();

                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                // Prévoit une éventuelle SoscketException
                try
                {
                    // Connexion au serveur
                    _socket.Connect(connection_Informations.address, connection_Informations.port);

                    // Teste si la connexion est établie
                    if (_socket.Connected)
                    {
                        MainForm.actual_MainForm.SetLogsBot("La connexion au serveur " + connection_Informations.server_Name + " est établie.");

                        _reception_Thread = new Thread(new ThreadStart(SocketReception));
                        _reception_Thread.Start();
                    }
                    else
                    {
                        MainForm.actual_MainForm.SetLogsBot("La connexion au serveur " + connection_Informations.server_Name + " a échoué.");
                    }
                }
                catch (SocketException sock_Ex)
                {
                    MainForm.actual_MainForm.SetLogsBot("[Socket Exception] " + sock_Ex.Message);
                    MainForm.actual_MainForm.TryReConnect(1);
                }
            }
        }
_parsing_Thread :

Code:
        private void SocketReception()
        {
            _buffer_Queue = new Queue();

            _parsing_Thread = new Thread(new ThreadStart(ParseBuffer)); // Lance le thread de traitement des paquets
            _parsing_Thread.Start();

            // Réception des données en boucle infinie durant la période connectée
            while ((_socket != null) && (_socket.Connected))
            {
                // Buffer
                byte[] buffer = new byte[_socket.Available];

                if (buffer.Length != 0)
                {
                    _socket.Receive(buffer);
                    _buffer_Queue.Enqueue(buffer); // Stockage du buffer dans une queue
                }
            }
        }
Au passage, la méthode ParseBuffer que j'ai un peu modifié depuis les derniers commentaires :

Code:
        private void ParseBuffer()
        {
            while ((_socket != null) && (_socket.Connected)) // On traite les paquets tant qu'on est connectés
            {
                if (_buffer_Queue.Count != 0) // Si la queue contient des buffers, on traite
                {
                    int index = 0;
                    ushort header;
                    ushort packet_ID = 0;
                    byte packet_Length_Type = 0;
                    int packet_Length = 0;
                    int packet_Start = 0;
                    int packet_End;
                    byte[] packet_Temporary;

                    byte[] packet_In = (byte[])_buffer_Queue.Dequeue();

                    MainForm.actual_MainForm.SetLogsBot("Buffer reçu : " + packet_In.Length.ToString());

                    // Lancement du timer de déconnexion en cas de non réception de buffer
                    //if (_timer_Parsing_Thread != null)
                    //{
                    //    _timer_Parsing_Thread.Change(Timeout.Infinite, Timeout.Infinite);
                    //}

                    _timer_Parsing_Thread = new System.Threading.Timer(TimerReceptionThreadFinished, null, 60000, 250);

                    if (_bytes_Wanted > 1) // Le buffer précédent ne contenait pas tout le message
                    {
                        packet_Temporary = new byte[packet_In.Length + _packet_Out.Length]; // Création du message temporaire
                        Array.Copy(_packet_Out, 0, packet_Temporary, 0, _packet_Out.Length); // Copie de début du message dans le message temporaire
                        Array.Copy(packet_In, 0, packet_Temporary, _packet_Out.Length, packet_In.Length); // Copie du buffer suivant dans le message temporaire
                        packet_In = packet_Temporary;
                    }

                    while (index < packet_In.Length) // Tant qu'il y a un header à lire dans le buffer
                    {
                        packet_Start = index;
                        header = (ushort)(packet_In[index] * 256 + packet_In[index + 1]); // Récupération de l'header
                        packet_Length_Type = (byte)(header & 3); // Récupération du type de longueur de message
                        packet_ID = (ushort)(header >> 2); // Récupération de l'ID du message
                        index += 2 + packet_Length_Type;

                        if (packet_ID == 6440)
                        {
                        }

                        switch (packet_Length_Type) // Récupération de l'hedaer
                        {
                            case 0:
                                packet_Length = 0;
                                break;
                            case 1:
                                packet_Length = packet_In[index - 1];
                                break;
                            case 2:
                                packet_Length = 256 * packet_In[index - 2] + packet_In[index - 1];
                                break;
                            case 3:
                                packet_Length = 65536 * packet_In[index - 3] + 256 * packet_In[index - 2] + packet_In[index - 1];
                                break;
                        }

                        if (index + packet_Length > packet_In.Length) // Le buffer ne contient pas tout le message
                        {
                            _bytes_Wanted = packet_Length - packet_Start;
                            _packet_Out = new byte[packet_In.Length - packet_Start];
                            Array.Copy(packet_In, packet_Start, _packet_Out, 0, packet_In.Length - index); // Copie le début du message dans un buffer
                        }
                        else
                        {
                            byte[] final_Packet = new byte[0];

                            if (packet_Length > 0)
                            {
                                final_Packet = new byte[packet_Length];
                                Array.Copy(packet_In, index, final_Packet, 0, packet_Length); // On copie le message final
                            }

                            MainForm.actual_MainForm.SetLogsBot("Paquet reçu, ID : " + packet_ID);

                            TreatPacket(packet_ID, final_Packet); // Traite le packet

                            index += packet_Length;
                            packet_End = index;

                            if (packet_End <= packet_In.Length) // Réinitialisation
                            {
                                _bytes_Wanted = 0;
                                _packet_Out = new byte[0];
                            }
                        }
                    }
                }
            }
        }

Et enfin _feeding_Thread :

Code:
        public void TryFeeding()
        {
            _feeding_Thread = new Thread(new ThreadStart(Feed));
            _feeding_Thread.Start();
        }
Il faut savoir que dans tout le code de ce commentaire, il y a TOUTES les références à TOUS mes threads.

Voilà ! :)
 
Haut Bas