matthieu637 / cpp-2a-info

CPP - Prépa des INP - Nancy | Projet Informatique 2ème année
https://matthieu637.github.io/cpp-2a-info/client.Reseau-class.html
MIT License
1 stars 4 forks source link

Problème déconnexion serveur (en local) #13

Closed david540 closed 7 years ago

david540 commented 7 years ago

Après avoir lancé 2 IA sur un serveur local (qui font énormément de demandes serveur), j'ai eu ce message d'erreur:

java.util.ConcurrentModificationException at java.util.TreeMap$PrivateEntryIterator.nextEntry(Unknown Source) at java.util.TreeMap$KeyIterator.next(Unknown Source) at java.util.AbstractCollection.toString(Unknown Source) at java.lang.String.valueOf(Unknown Source) at network.Client.run(Client.java:137)

ça ressemble à un problème de threads non ? Après cette exception mes IA ont encore fait quelques demandes, puis plus rien, les IA ne sont plus avertis que la partie et fini et quand l'hôte fait un del(r), le serveur n'affiche pas "Client déconnecté" et les IA ne reçoivent toujours pas de messages d'erreurs les IA reçoivent un message d'erreur seulement quand je déconnecte le serveur

david540 commented 7 years ago

Et j'ai aussi eu quelques fois des IA qui étaient déconnecté du serveur en pleine partie sans raison: File "C:\Users\David\Desktop\Bourse_reseau\clientLastVersion.py", line 133, in __recevoir raise RuntimeError("Connexion perdu. _5") RuntimeError: Connexion perdu. _5

david540 commented 7 years ago

ok une réseau pour la déconnection des clients est surement ça : File "C:\Users\David\Desktop\Bourse_reseau\clientLastVersion.py", line 356, in ventes return eval(self.__recevoir()) File "", line 1 [('banque',25.0,39944), ('Bot92',25.002619,1), ('Bot92',25.023281,1), ('Bot92',25.043905,1), ('Bot92',25.064491,1), ('Bot92',25.085037,1), ('Bot92',25.105547,1), ('Bot92',25.126017,1), ('Bot92',25.14645,1), ('Bot92',25.166843,1), ('Bot92',25.1872,1), ('Bot92',25.207521,1), ('Bot92',25.227804,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049 ,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot9 2',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.24804 9,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot 92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.2480 49,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bo t92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248 049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('B ot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.24 8049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), (' Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.2 48049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ( 'Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25. 248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25 .248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',2 5.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1) , ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92', 25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1 ), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92' ,25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049, 1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92 ',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049 ,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot9 2',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.24804 9,1), ('Bot92',25.248049,1), ('Bot92',25.248049,1), ('Bot92',25.2480

C'est la longueur de mes ventes qui font des messages réseaux énormes, déjà on pourrait ignorer les ventes supérieur à 25 euros et les achats inférieurs à 0.25 non ? Ensuite je ne sais pas si ça va réellement être possible de lister tous les achats et ventes, peut être plutôt les 20 meilleurs ?

david540 commented 7 years ago

J'ai modifié en gardant que les 20 meilleurs, j'ai résolu l'une des erreur mais pas celle là java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at java.util.AbstractCollection.toString(Unknown Source) at java.lang.String.valueOf(Unknown Source) at network.Client.run(Client.java:137)

matthieu637 commented 7 years ago

Une fois qu'une exception non gérée est levée par le serveur, il s'arrête complètement. Essaie d'ajouter le nom clé synchronized dans les méthodes core.Marche::getListeAchats et core.Marche::getListeVentes pour voir si cela résout le problème.

Pour la longueur de la requête est-ce que tu pourrais me donner sa taille ? (en nombre de caractère)

matthieu637 commented 7 years ago

Pour ce qui est de lister les 20 meilleurs, c'est justement la contribution suivante :

Néanmoins, j'aimerais qu'il soit tout de même possible de tout récupérer en gardant r.ventes('Facebook').

matthieu637 commented 7 years ago

L'exception vient du fait que tu essaies, à la fois, de lire les ventes et d'écrire dessus. Synchronized devrait résoudre le problème, sinon je le ferrai avec un mutex.

david540 commented 7 years ago

J'ai ajouté les Synchronized et j'ai surchargé la fonction getListeVentes, on appelle la première si la longueur demandée est trop grande ou inférieur ou égale à 0 et la deuxième sinon (pour pas qu'il y est d'erreur avec le sublist et pour ne pas faire de cast si on veut toute la liste) public synchronized Set getListeVentes(Action a) { return liste_ventes.get(a); } public synchronized List getListeVentes(Action a, int longueurMaxListe) { return (new LinkedList(liste_ventes.get(a))).subList(0, longueurMaxListe); } Mais malgrès le synchronized j'ai ce message d'erreur qui porte sur la deuxieme fonction: java.util.ConcurrentModificationException 8 3 11.12 1

Client déconnecté at java.util.TreeMap$PrivateEntryIterator.nextEntry(Unknown Source) at java.util.TreeMap$KeyIterator.next(Unknown Source) at java.util.AbstractCollection.finishToArray(Unknown Source) at java.util.AbstractCollection.toArray(Unknown Source) at java.util.LinkedList.addAll(Unknown Source) at java.util.LinkedList.addAll(Unknown Source) at java.util.LinkedList.(Unknown Source) at core.Marche.getListeVentes(Marche.java:126) at network.Client.run(Client.java:145)

Cette exception déconnecte seulement le client mais pas le serveur

matthieu637 commented 7 years ago

J'ai revu le système de concurrence des threads (9d82199e3f4eca2121c2475aa1381964ffca5c2a). Tu peux essayer avec cette nouvelle version.

matthieu637 commented 7 years ago

Si j'ai bien suivi, les exceptions serveurs sont résolues #14.

Par contre, ça m'intéresserait de savoir si en utilisant r.achats(actions) sans limiter la taille, tu arrives encore à déclencher l'exception client que tu décris dans ton commentaire 3. Et si c'est le cas, quelle est la taille de la chaîne reçu (supérieur à 99999999 ?)?

david540 commented 7 years ago

Oui il y a encore un problème si la liste est trop grande J'ai mis un print(len(back.decode())) pour suivre la taille des chaines reçus Deux des clients ont eu une exception vers 2800 caractère et un autre vers 3800 donc il n'y a pas l'air d'avoir de limite. Au faite je ne l'avais pas dis mais l'erreur est un SyntaxError: EOL while scanning string literal et qui apparait quand les chaines sont très grandes.

matthieu637 commented 7 years ago

La seconde exception devrait être fixée par ces modifications : (83feb994eeae9925d498f2b734d4b6f7f536c5d4). Tu peux re-sync. Est-ce bien le cas?

david540 commented 7 years ago

Non malheureusement ça n'a pas résolu le problème, voici l'exception complète côté client (il n'y a aucune erreur détectée côté serveur):

Traceback (most recent call last): File "C:\Users\David\Desktop\Bourse_reseau\IAorganise.py", line 135, in bourse.maj() File "C:\Users\David\Desktop\Bourse_reseau\IAorganise.py", line 54, in maj self.lVentes[action]=self.r.ventes(action) File "C:\Users\David\Desktop\Bourse_reseau\clientLastVersion.py", line 371, in ventes return eval(self.__recevoir()) File "", line 1 [('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('B ot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54 ',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14 .71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71, 1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bo t54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54' ,14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14. 71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1 ), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ( 'Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot 54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54', 14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.7 1,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1) , ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), (' Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot5 4',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',14.71,1), ('Bot54',1 4.71,1), ('Bot54 ^ SyntaxError: EOL while scanning string literal

matthieu637 commented 7 years ago

Je me suis trompé lors du merge. Mon code a été effacé. Tu peux re-sync et essayer (28249524fb2c8587ba4635f97cf9d7022bb7dc01).

david540 commented 7 years ago

J'avais déjà copié collé ce nouveau __recevoir(), J'ai eu une erreur EOF cette fois SyntaxError: unexpected EOF while parsing

matthieu637 commented 7 years ago

Est-ce que tu pourrais me donner le code minimal permettant de reproduire le bug à coup sur ?

david540 commented 7 years ago

Oui je vais essayer d'en faire un, Le problème vient peut être du OutputStreamWriter::out.write(packet) J'ai lu qu'il y avait une taille max de 8192 caractères et quand je remplace le out.write(packet) par out.write(packet,0,500) quand packet.size()>500 j'ai le même type d'erreur (mais beaucoup plus tôt) ça n'expliquerait pas par contre pourquoi il y a ce problème à seulement 3000 caractères s'il vient de ça

matthieu637 commented 7 years ago

C'était le cas avec le BufferedWriter, c'est pour ça que j'ai changé à OutputStreamWriter. Si la taille est plus grande que celle d'un paquet TCP, plusieurs paquets seront envoyés. Je ne pense pas que ce soit le serveur java qui ajoute un caractère EOL ou EOF.

Est-ce que tu peux essayer de lancer tes scripts sur le serveur officiel ? Pour voir si tu as aussi des exceptions. J'ai l'impression que ça pourrait venir du système d'exploitation. Sous Linux (serveur et client), je n'ai pas de problème même avec des requêtes de taille supérieur à 60 000 bytes.

david540 commented 7 years ago

C'est bon je pense avoir résolu le problème, en poursuivant l'idée que vous avez eu pour la lecture côté client.py, j'ai mis ça: int compteur=0,keep=packet.length(); while(keep>1000){ out.write(packet,1000compteur,1000(compteur+1)); out.flush(); compteur++; keep=packet.length()-(1000compteur); } out.write(packet,1000compteur,packet.length()); out.flush(); Et maintenant ça marche

david540 commented 7 years ago

Ah non je n'ai rien dis, le serveur a levé une exception Je vais essayer sur le serveur officiel alors

david540 commented 7 years ago

Oui même problème avec le serveur officiel ^ SyntaxError: EOL while scanning string literal

matthieu637 commented 7 years ago

Il me faudrait un code minimal pour que je puisse reproduire l'erreur de mon côté.

david540 commented 7 years ago

from client import Reseau from random import*

r=Reseau("localhost",23456)

pseudo="Bot"+str(int(random()100)) cle=25670#A changer pour chaque partie while r.rejoindrePartie(cle,pseudo)<0: pseudo="Bot"+str(int(random()100)) r.top() while int(r.fin()['temps'])>0: r.bid("Facebook",1,1) r.ventes("Facebook")

david540 commented 7 years ago

Il faut créer la partie manuellement, mettre la clé de la partie dans le code puis lancer 5 shells avec ce programme

david540 commented 7 years ago

Effectivement chez moi il y a un ajout d'un EOL ou EOF tout seul, avec ce code ça marche :

def __recevoir(self):
        try:
            length = self.__sock.recv(8)
            if length == b'':
                raise RuntimeError("Connexion perdu. _5")
            length=int(length.decode())
            result=''
            while True:
                keep = length - len(result)
                if keep > 4096:
                    back = self.__sock.recv(4096)
                    if back == b'':
                        raise RuntimeError("Connexion perdu. _3")
                    result += back.decode()
                else:
                    back = self.__sock.recv(keep)
                    if back == b'':
                        raise RuntimeError("Connexion perdu. _6")
                    result += back.decode()
                    break
                result=result[:len(result)-1] #On supprime le dernier caractere de la str temporaire

            return result
david540 commented 7 years ago

Ca vient de client.py mais si les systèmes d'exploitations gèrent ça différemment ça va être compliqué, un test if (result[-1] == 'EOF' or result[-1] == 'EOL'): result=result[:-1] à la fin de la boucle while True ?

david540 commented 7 years ago

Non je me suis trompé c'était pas ça le problème, là ça marche tout le temps

def __recevoir(self):
    try:
        length = self.__sock.recv(8)
        if length == b'':
            raise RuntimeError("Connexion perdu. _5")
        length=int(length.decode())
        result=''
        while True:
            keep = length - len(result)
            if keep > 4096:
                back = self.__sock.recv(4096)
                if back == b'':
                    raise RuntimeError("Connexion perdu. _3")
                result += back.decode()
            else:
                back = self.__sock.recv(keep)
                if back == b'':
                    raise RuntimeError("Connexion perdu. _6")
                result += back.decode()
                if length == len(result): # ICI sinon des fois il y a break sans que le client ait lu tout le message du client, si les parties du messages du client n'ont pas pour taille 4096
                    break

        return result
    except (ConnectionRefusedError):
        raise RuntimeError("Connexion perdu. _4")
david540 commented 7 years ago

Dans certains cas, la découpe ne doit peut être pas se faire tout les 4096 bytes, le problème venait de là je crois, le break était call sans que tout le message soit reçu

matthieu637 commented 7 years ago

Félicitations, il n'a pas été simple à trouver.