Bug socket linux windows

Résolu/Fermé
Flayme - Modifié le 5 déc. 2022 à 12:04
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 9 déc. 2022 à 15:16

Bonjour,

Je suis en train de créer un jeu en ligne via le module socket.

Quand je lance le serveur et 2 clients depuis mon ordinateur windows ça marche.

Mais quand je lance n'importe quel programme (serveur ou client) depuis mon ordinateur linux, l'application ne marche pas (erreur -> json decode error ou aucune erreur et le programme attend)

Voici mon code:

server.py

import socket
import threading
import json
import random

class Server:
    def __init__(self, addr, port):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.bind((addr, port))
        self.CARTES = (0, 1)
        self.GEARS = (0, 1)
        self.ok_message = "OK!"
        self.nope_message = "NOPE!"
        self.DECO = "DECO!"
        self.games = {}
        self.names = {}
        self.map_ok = {}
        self.map = {}
        self.gear_ok = {}
        self.gear = {}
        
    def start(self):
        self.server.listen()
        while True:
            conn, _ = self.server.accept()
            threading.Thread(target=self.handle_client, daemon=True, args=(conn, )).start()
    
    @staticmethod
    def recv(conn):
        inf = conn.recv(1024).decode()
        print(inf)
        try:
            return json.loads(inf)[0]
        except json.decoder.JSONDecodeError:
            return json.loads(repr([inf, ]))
    
    @staticmethod
    def send(conn, msg):
        conn.send(json.dumps([msg,]).encode())
    
    def handle_client(self, conn):
        # get username
        while True:
            username = self.recv(conn)
            if username in self.names.values():
                self.send(conn, self.nope_message)
            else:
                self.send(conn, self.ok_message)
                self.names[conn] = username
                break
            
        # get type_game
        type_game = self.recv(conn)
        if not self.games.get(type_game, False):
            self.games[type_game] = [conn, ]
        else:
            self.games[type_game].append(conn)
            
        # get game
        while True:
            id_game = len(self.games[type_game])
            while len(self.games[type_game]) < 2:
                pass
            if id_game == 1:
                opp = self.games[type_game][id_game]
                break
            elif id_game == 2:
                opp = self.games[type_game][id_game - 2]
                break
        self.send(conn, self.ok_message)
        self.recv(opp)
        self.games[type_game].pop(self.games[type_game].index(conn))
        self.send(conn, [id_game, self.names[opp]])
        
        # get map
        carte = None
        while carte not in self.CARTES:
            carte = self.recv(conn)
            if carte in self.CARTES:
                self.send(conn, self.ok_message)
                self.map[conn] = carte
                break
            else:
                self.send(conn, self.nope_message)
        
        if id_game == 1:
            if self.map_ok.get((conn, opp)) is None:
                self.map_ok[(conn, opp)] = [True, False]
            else:
                self.map_ok[(conn, opp)] = [True, True]
            while not all(self.map_ok[(conn, opp)]):
                pass
            carte = random.choice([self.map[conn], self.map[opp]])
            self.send(conn, carte)
            self.send(opp, carte)
        else:
            if self.map_ok.get((opp, conn)) is None:
                self.map_ok[(opp, conn)] = [True, False]
            else:
                self.map_ok[(opp, conn)] = [True, True]   
                     
        # gear
        print("GETTING GEAR")
        gear = None
        while gear not in self.GEARS:
            gear = self.recv(conn)
            ok = True
            for g in gear:
                if g not in self.GEARS:
                    ok = False
                    break
            if ok:
                self.send(conn, self.ok_message)
                self.gear[conn] = gear
                break
            else:
                self.send(conn, self.nope_message)
        
        if id_game == 1:
            if self.gear_ok.get((conn, opp)) is None:
                self.gear_ok[(conn, opp)] = [True, False]
            else:
                self.gear_ok[(conn, opp)] = [True, True]
            while not all(self.gear_ok[(conn, opp)]):
                pass
            print(self.gear[opp], self.gear[conn])
            self.send(conn, self.gear[opp])
            self.send(opp, self.gear[conn])
        else:
            if self.gear_ok.get((opp, conn)) is None:
                self.gear_ok[(opp, conn)] = [True, False]
            else:
                self.gear_ok[(opp, conn)] = [True, True]
        
        # game
        while True:
            msg = self.recv(opp)
            self.send(conn, msg)

if __name__ == "__main__":
    server = Server("localhost", 5070)
    server.start()

game.py

from networking import Client
import game

import pygame


def test(addr, port):
    x = y = x2 = y2 = 100
    j_moi = pygame.Surface((50, 50))
    j_moi.fill((255, 0, 0))
    
    j_opp = pygame.Surface((50, 50))
    j_opp.fill((0, 0, 255))
    clock = pygame.time.Clock()    
    
    aff_win = True
    run = True
    with Client(addr, port) as client:
        # get some info
        name = input("Entrer un nom d'utilisateur: ")
        while not client.get_username(name):
            print("nom deja utilise!")
            name = input("Entrer un nom d'utilisateur: ")
        
        moi_aff = game.Afficher((0, 0), name, (0, 0, 0), 30)

        id_game, opp = client.get_game("!PUBLIC")
        print("id_game:", id_game)
        print("opp:", opp)
        opp_aff = game.Afficher((0, 0), opp, (0, 0, 0), 30)
        
        while True:
            carte_inp = input("Entrer une carte: ")
            try:
                carte_inp = int(carte_inp) - 1
            except ValueError:
                print("Entrer le nombre de la carte!")
                continue
            carte = client.get_map(carte_inp)
            if carte is not None:
                break
            print("map n'existe pas!")
        
        print("carte:", carte)
        
        # gear
        while True:
            gear = []
            for i in range(game.GEAR_LEN):
                while True:
                    inp = input("Entrer gear "+str(i + 1)+": ")
                    try:
                        inp = int(inp) - 1
                        break
                    except ValueError:
                        print("Veuillez entrer le nombre du gear que vous voulez utiliser!")
                gear.append(inp)
            gear_opp = client.get_gear(gear)
            if gear_opp is not None:
                break
            print("gear n'existe pas!")

        print("gear opp:", gear_opp)
        
        # game
        pygame.init()
        screen = pygame.display.set_mode((game.width, game.height))
        pygame.display.set_caption(name)
        
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    run = False
                    aff_win = False
                    break
            if not run:
                break
            key = pygame.key.get_pressed()
            if key[pygame.K_UP]:
                y -= game.base_J_DEP[0]
            if key[pygame.K_DOWN]:
                y += game.base_J_DEP[0]
            if key[pygame.K_LEFT]:
                x -= game.base_J_DEP[0]
            if key[pygame.K_RIGHT]:
                x += game.base_J_DEP[0]
            
            info = client.dialogue([x, y])
            if len(info) == 1:
                if info == client.DECO:
                    print("L'ADVERSAIRE C'EST DÉCONNECTER!!!!!")
                    run = False
            elif len(info) == 2:
                x2, y2 = info
                
            moi_aff.update(x=x + moi_aff.surface.get_width()//2, y=y - moi_aff.surface.get_height())
            opp_aff.update(x=x2 + opp_aff.surface.get_width()//2, y=y2 - opp_aff.surface.get_height())

            screen.fill((255, 255, 255))
            screen.blit(j_moi, (x, y))
            screen.blit(j_opp, (x2, y2))
            moi_aff.draw(screen)
            opp_aff.draw(screen)
            pygame.display.update()
            clock.tick(60)


if __name__ == "__main__":
    addr = input("Entrer l'address: ")
    while True:
        port = input("Entrer le port: ")
        try:
            port = int(port)
            break
        except ValueError:
            print("Veuillez entrer un nombre entier pour le port.")
    test(addr, port)

dossier networking:

__init__.py

from .client import *

client.py

import socket
import json


class Client:
    def __init__(self, addr, port):
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client.connect((addr, port))
        self.DECO = "DECO!"
        self.ok_message = "OK!"
        self.nope_message = "NOPE!"
        
    def send(self, msg):
        print("sending:", msg)
        self.client.send(json.dumps([msg]).encode())
        
    def recv(self):
        infos = self.client.recv(1024).decode()
        print(infos)
        return json.loads(self.client.recv(1024).decode())[0]

    def dialogue(self, msg):
        self.send(msg)
        return self.recv()
    
    def __enter__(self):
        return self
        
    def __exit__(self, *_):
        self.send(self.DECO)
        
    def get_game(self, msg):
        self.dialogue(msg)
        return self.dialogue(self.ok_message)
    
    def get_username(self, msg):
        return self.dialogue(msg) == self.ok_message
    
    def get_map(self, msg):
        self.send(msg)
        if self.recv() == self.ok_message:
            return self.recv()
        
    def get_gear(self, msg):
        self.send(msg)
        if self.recv() == self.ok_message:
            return self.recv()

le dossier game:

__init__.py

from .sprite import Sprite
from .afficher import Afficher
from .get_path import path, separator
from .data import *

sprite.py

import pygame


class Sprite:
    __list = []

    @classmethod
    def get_list(cls):
        return cls.__list

    def __init__(self, coord: (int, int), surface: pygame.Surface):
        self.alive = True
        self.show = True
        self.x, self.y = coord
        self.surface = surface
        self.mask = pygame.mask.from_surface(self.surface)
        self.__list.append(self)
        self.nb = len(self.__list)
        self.nom = "Sprite{}".format(self.nb)

    def draw(self, screen: pygame.Surface):
        if self.alive and self.show:
            screen.blit(self.surface, (self.x, self.y))

    def is_coliding(self, m):
        if m == "all":
            check = self.__list
            check.remove(self)
        elif type(m) == tuple or type(m) == list or m is None:
            check = m
            if m == () or m == [] or m is None:
                return
        elif hasattr(m, "mask") and hasattr(m, "x") and hasattr(m, "y"):
            check = (m,)
        else:
            raise (ValueError("parameter m is not valid, please enter \"all\" "
                              "or a Mask or a tuple/list of Mask: not a {}".format(type(m))))
        res = []
        for sprite in check:
            if self.mask.overlap_mask(sprite.mask, (sprite.x - self.x, sprite.y - self.y)).count() != 0:
                try:
                    if sprite.alive:
                        res.append(sprite)
                except AttributeError:
                    res.append(sprite)
        return res

    def __str__(self):
        return self.nom

    def __repr__(self):
        return "{}->x:{},y:{}".format(self.nom, self.x, self.y)

    def check_alive(self):
        if not self.alive:
            self.__list.remove(self)

    def update(self):
        self.check_alive()

afficher.py

from .sprite import Sprite
from .get_path import path
import pygame


class Afficher(Sprite):
    def __init__(self, coord, texte, color, taille):
        police = pygame.font.Font(path+"arial_narrow_7.ttf", taille)
        texte_surface = police.render(texte, True,
                                      pygame.Color(color))
        super().__init__(coord, texte_surface)
        self.texte = texte
        self.taille = taille
        self.color = color
        self.nom = "Afficher{}".format(self.nb)

    def update(self, texte=None, x=None, y=None):
        if texte is not None:
            police = pygame.font.Font(path+"arial_narrow_7.ttf", self.taille)
            self.surface = police.render(texte, True,
                                         pygame.Color(self.color))
        if x is not None:
            self.x = x
        if y is not None:
            self.y = y
        self.check_alive()

get_path.py

import os
import sys
separator = "/" if sys.platform == "linux" else "\\"

path = __file__.split(separator)
path = path[:-1]
_ = ""
for p in path:
    _ += p + (separator)
path = _

data.py

import pygame

from .get_path import path
from .mur import Mur

pygame.init()
width, height = pygame.display.Info().current_w - 70, pygame.display.Info().current_h - 70

maps = [{"mur": [Mur(0, -100, width, 100), Mur(width, 0, 100, height), Mur(0, height, width, 100),
                 Mur(-100, 0, 100, height), Mur(-100, 0, 100, height),
                 Mur(width // 7, height // 3.3, 30, width // 4.5),
                 Mur(width // 7 * 6, height // 3.3, 30, width // 4.5),
                 Mur(width // 2 - 15, 0, 30, height // 6 + 10),
                 Mur(width // 2 - 15, height // 6 * 5, 30, height // 6 + 10)]}, ]

GEAR_LEN = 8
WH_PLAYER = 100
WH_TIR = 10

base_J_DEP = (10, 3)
base_J_VIE = 100

base_TIR_DEP = (15, 3)
base_TIR_DEGAT = 3

base_background = pygame.image.load(path + "space.png")
base_background = pygame.transform.scale(base_background, (width, height))

base_j1_image = pygame.image.load(path + "wizard_bleu.png")
base_j1_image = pygame.transform.scale(base_j1_image, (WH_PLAYER, WH_PLAYER))
base_j1_image.set_colorkey((255, 255, 255))

base_j1_image_wand = pygame.image.load(path + "wand_bleu.png")
base_j1_image_wand = pygame.transform.scale(base_j1_image_wand, (WH_PLAYER, WH_PLAYER))
base_j1_image_wand.set_colorkey((255, 255, 255))

base_j2_image = pygame.image.load(path + "wizard_rouge.png")
base_j2_image = pygame.transform.scale(base_j2_image, (WH_PLAYER, WH_PLAYER))
base_j2_image.set_colorkey((255, 255, 255))

base_j2_image_wand = pygame.image.load(path + "wand_rouge.png")
base_j2_image_wand = pygame.transform.scale(base_j2_image_wand, (WH_PLAYER, WH_PLAYER))
base_j2_image_wand.set_colorkey((255, 255, 255))

base_j1_image_tir = pygame.Surface((WH_TIR, WH_TIR))
base_j1_image_tir.fill((0, 0, 255))

base_j2_image_tir = pygame.Surface((WH_TIR, WH_TIR))
base_j2_image_tir.fill((255, 0, 0))

(-> jeu pas fini)

(pour ce qui veulent tester le jeu pour m'aider il faut aller télécharger la police arial narrow7.ttf.

Je pense que les erreurs viennent de socket.

J'ai essayé cette commande (sur linux) lorsque je cherchais une solution:

sysctl -w net.ipv4.tcp_timestamps=0

Rien n'a changé. Si vous n'avez pas tout compris, posez des questions et merci de m'aider à résoudre mon problème,

Flayme

A voir également:

4 réponses

correction:

Ça ne marche pas seulement avec le "ngrok" que j'utilise

0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 811
5 déc. 2022 à 12:13

Bonjour,

Merci quand tu partages de préciser dans la cellule de code le langage de programmation (python).

Autant que possible, évite de mettre tout ton programme pour parler d'un problème précis. Il faut plutôt construire un exemple minimal qui met en évidence le problème, nous expliquer comment tu le lances, le comportement observé et le comportement attendu. Ici une grande partie du code partagé n'a vraisemblablement rien à avoir avec ton problème.

Vu que le projet est volumineux et contient des ressources qui ne sont pas du code (polices, images...) il vaudrait mieux mettre ton projet par exemple sur github et nous donner l'adresse du dépôt. Car là, il manque des fichiers pour tester ton code.

Je te propose de repartir sur cet exemple relativement minimal qui montre comment écrire en pygame un jeu multijoueur ou chaque joueur peut depuis sont client déplacer un carré qui lui est propre et voir le carré des autres joueurs.

Bonne chance

0

Merci pour le programme, mais j'ai réussi à l'écrire moi-même. Pour le reste, je le ferai la prochaine fois.

0

Salut, si tu souhaites avoir de l'aide afin d'identifier ce qui cloche, fais un zip de ton application que tu hébergeras quelque part afin que l'on ait pas à copier/coller chacun de tes codes dans chaque fichier, et surtout que l'on a juste à lancer ton programme pour pouvoir le déboguer, et si possible réduire au minimum ton script, il n'y a certainement pas besoin de tout ces fichiers, essaie d'identifier celui où cela bogue, client, serveur, et json, pas besoin de pygame et tous ces packages.

Sinon, comme d'habitude, des prints, des exceptions pour comprndre où ton programme plante. Déjà je vois un ÉNORME problème, c'est que tu as un fichier game, et un package game, nomme les différemment ! Même si ça fonctionne en l'état.

Bon courage.

0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 811
5 déc. 2022 à 13:31

Je pense que c'est voulu, ainsi import game importe game/__init__.py qui lui même importe toute une série de fichiers en cascade.

0

ok

0

Pour corriger mon bug, j'ai encadré tout mes messages avec un caractère: "^" ce qui permet de savoir exactement ou commence et ou finit le message pour ne pas avoir d'interférence. Avant cela, il faut vérifier si le caractère est dans le message pour éviter les problèmes.

Je ne sais pas comment on fait pour marquer résolu ma question, donc si un modérateur pouvait le faire pour moi ce serait gentil.

Merci quand même d'avoir essayer de m'aider

Au revoir

Flayme

0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 811
Modifié le 9 déc. 2022 à 15:53

Pour marquer une discussion en résolu, il faut faire comme expliqué dans ce lien, mais cela nécessite d'avoir un compte CCM. Bref, je m'en occupe.

Concernant ton problème, je reste un peu sceptique sur la manière dont tu l'as résolu. Voici un petit exemple qui met en évidence un client qui envoie chaque seconde une chaîne de caractère à 5 reprises vers un serveur qui réécrit le message reçu sur sa sortie standard. Comme tu peux le voir, il n'y a pas de délimiteur impliqué dans le code.

  • server.py
import socket

SERVER_BIND_ADDRESS = "localhost"
SERVER_PORT = 8000

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    print(f"Starting server {SERVER_BIND_ADDRESS}:{SERVER_PORT}")
    server.bind((SERVER_BIND_ADDRESS, SERVER_PORT))
    server.listen()                               
    (client, client_addr) = server.accept()       
    with client:                     
        print(f"New client {client_addr}")
        while True:
            data = client.recv(1024)  # Fetch the data, 1024 bytes by 1024 bytes
            if not data:
                break  # No more data to fetch
            message = data.decode("utf-8")
            print(message)
  • client.py
import socket
from time import sleep

SERVER_HOST = "localhost"  # The server's hostname or IP address
SERVER_PORT = 8000         # The port used by the server

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    print(f"Connect to {SERVER_HOST}:{SERVER_PORT}")
    client.connect((SERVER_HOST, SERVER_PORT))
    for i in range(5):
        client.sendall(bytes(f"Hello, world {i}", "utf-8"))
        sleep(1)
  • Utilisation
    • Lancer server.py dans un terminal
    • Puis lancer client.py dans un autre terminal
  • Résultat (terminal server.py)
Starting server localhost:8000
New client ('127.0.0.1', 60514)
Hello, world 0
Hello, world 1
Hello, world 2
Hello, world 3
Hello, world 4

Bonne continuation.

1