alka93
Messages postés3Date d'inscriptionmercredi 24 mai 2023StatutMembreDernière intervention24 mai 2023
-
24 mai 2023 à 02:34
alka93
Messages postés3Date d'inscriptionmercredi 24 mai 2023StatutMembreDernière intervention24 mai 2023
-
24 mai 2023 à 23:41
Bonjour,
Dans le cadre de mon projet qui consiste à la mise en place d’une application de Tchat sous python
L’objectif est de proposer un système client-serveur permettant à plusieurs utilisateurs de se connecter sur le serveur et de pouvoir se communiquer avec les autres utilisateurs via ce dernier.
Vous devez être en mesure de permettre à ces utilisateurs de se connecter sur l’application de chat via une interface de connexion. Il doit être déjà inscrit.
Une fois connecté il est directement redirigé vers l’interface de Tchat.
Si l’utilisateur envoie un message il sera diffusé à tous les autres utilisateurs sauf celui qui a envoyé ce message.
L’utilisateur s’il le désire aura la possibilité d’envoyer des messages à un seul utilisateur parmi ceux qui sont connectés.
Bon pour le moment la partie consacrée à l'envoi des messages par diffusion multicast est déjà achevée et il me reste la partie unicast réservée à l'envoi de messages ciblés privées unicast dont je n'arrive pas à gérer . Du coup je compte sur un appui de quelqu'un à travers cette plateforme d'échange et de partage pour pouvoir terminer l'application.
voici le code coté serveur :
import tkinter as tk
from socket import *
from threading import Thread
class ChatServerGUI(tk.Tk):
def __init__(self):
super().__init__()
self.title("Serveur de Chat")
self.geometry("400x300")
self.text_area.insert(tk.END, "Le serveur écoute sur le port {}\n".format(port))
self.text_area.insert(tk.END, "Serveur démarré sur le port {}\n".format(port))
def broadcast_message(self, message, sender_socket):
for client in self.clients:
if client is not sender_socket:
client.send(message.encode("utf-8"))
def unicast_message(self, recipient_address, message):
recipient_socket = None
for client_socket in self.clients:
client_address = client_socket.getpeername()
if client_address[0] == recipient_address[0] and str(client_address[1]) == recipient_address[1]:
recipient_socket = client_socket
break
if recipient_socket is not None:
recipient_socket.send(message.encode("utf-8"))
self.text_area.insert(tk.END, "Message unicast envoyé à {}: {}\n".format(recipient_address, message))
else:
self.text_area.insert(tk.END, "Impossible d'envoyer le message unicast à {}: Client non trouvé\n".format(recipient_address))
def stop_server(self):
for client in self.clients:
client.close()
self.server_socket.close()
self.text_area.insert(tk.END, "Serveur arrêté\n")
self.quit()
if __name__ == "__main__":
server = ChatServerGUI()
server.mainloop()
voici le code coté client:
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
import socket
from threading import Thread
import datetime
# Vérifier si la conversation privée existe déjà
if recipient in self.private_conversations:
private_chat = self.private_conversations[recipient]
private_chat.append("[Vous][{}]: {}".format(recipient, message))
else:
# Créer une nouvelle conversation privée
private_chat = ["[Vous][{}]: {}".format(recipient, message)]
self.private_conversations[recipient] = private_chat
def receive_messages(self):
try:
while True:
message = self.client_socket.recv(1024).decode()
if message.startswith("[CONNECTED_USERS]"):
connected_users = message[17:].split(',')
self.connected_users_callback(connected_users)
elif message.startswith("[PRIVATE]"):
self.handle_private_message(message)
else:
self.text_area.insert(tk.END, message + "\n")
except ConnectionError:
messagebox.showinfo("Information", "La connexion au serveur a été interrompue.")
self.disconnect_callback()
except ValueError:
messagebox.showerror("Erreur", "Le port doit être un nombre entier.")
except ConnectionRefusedError:
messagebox.showerror("Erreur", "La connexion au serveur a été refusée.")
Ton code est plutôt long, je l'ai lu en diagonale.
Je me demande toujours pourquoi on fait du multithreading avec les socket ...
Je suppose que tous tes utilisateurs ont un pseudonyme.
Dans ce système, on ne peut pas entrer de commande, donc tu ne sais pas comment envoyer un message personnel? Est-ce là le seul problème?
Je pourrais suggérer ceci:
avant le broadcast, tu vérifies si le message commence par un caractère spécial, disons le '@'
si le message commence par '@', tu supposes que ce qui suit est un pseudonyme (jusqu'au premier espace).
Tu vérifies si le pseudonyme est connecté.
Si oui, tu initialises un échange personnel, sinon tu envoies un message d'erreur à l'envoyeur.
En fait, je n'ai pas compris si tu passais dans un autre mode ou si les messages personnels sont ponctuels et si le récepteur doit répondre de la même façon.
Dans ce cas, le message suivrait le pseudonyme.
exemple: tu m'envoies un message:
@PierrotLeFou pourquoi m'as-tu envoyé ce message que tous le monde reçoit?
je te répond:
@alka93 Je ne savais pas comment t'envoyer un message personnel.
Ça peut ouvrir la porte à d'autres applications.
Si je veux avoir la liste de toutes les personnes connectées:
@@list
je veux savoir si un usager est connecté:
@@connected Einstein
alka93
Messages postés3Date d'inscriptionmercredi 24 mai 2023StatutMembreDernière intervention24 mai 2023 24 mai 2023 à 23:41
voici le résultat de mes test par envoi broadcast et unicast .
pour ce test c'est obrian qui envoi un message privé à badman et ce dernier reçoit ceci
alka93
Messages postés3Date d'inscriptionmercredi 24 mai 2023StatutMembreDernière intervention24 mai 2023 24 mai 2023 à 04:36
Merci pour votre suggestion .
je pense selon votre analyse j'ai déjà fait de tout ce qui est envoi par broadcast à tous les utilisateurs connectés au niveau du serveur mais mon problème majeur se trouve au niveau de l'envoi unicast c'est à dire l'envoi de messages privés à u tiers pour expliciter davantage quant trois utilisateurs se connectent avec les pseudos respectifs jean , Paul et Antoine . si Jean veut envoyer un message privé à Paul il choisira comme destinataire le pseudo de Paul sur le champ de saisi destinataire ce dernier à son tour recevra le message envoyé par jean en privé excepté de Antoine qui n'aura pas aces à ce message au niveau de sa zone de tchat .
grosso modo dans un premier temps il s'agit de faire un envoi diffusé à tous les user et dans un second un envoi ciblé et privé .
Bien sûr que j'ai utilisé un séparateur pour ca le code fonctionne bien le problème est que au niveau de cet envoi unicast comme je l'ai démontré ci dessous l'utilisateur Antoine a reçu ce message qui était destiné à Paul et non lui .c'est ce qui m'étonne
Si je considère la ligne suivante:
if client_address[0] == recipient_address[0] and str(client_address[1]) == recipient_address[1]:
Pourquoi convertis-tu le premier [1] en str et pas l'autre?
Il faudrait déjà que ton code fasse que ta méthode unicast_message soit utilisée, ce n'est pas le cas.
Il y a aussi un problème avec le server qui ne se ferme pas (lock_acquire fail), obligé de le kill avec le terminal, aussi mettre le foreground du text, car chez moi (avec mon thème graphique) c'est blanc sur blanc, donc invisible, les fenêtres clients ne font pas apparaître les champs de saisies et boutons si on ne met en plein écran.
Ton code devrait aussi séparer les applications serveur, client des interfaces graphiques, ce serait bien plus lisible, et plus modulable, c-à-d pouvoir l'utiliser dans un autre type d'environnement, simple console, autres GUI, etc.
Sinon, complètement d'accord avec PierrotLeFou concernant le @ qui est devenu un standard dans les chats.
24 mai 2023 à 23:41
voici le résultat de mes test par envoi broadcast et unicast .
pour ce test c'est obrian qui envoi un message privé à badman et ce dernier reçoit ceci
127.0.0.1:56567 says: [obrian]: salut
127.0.0.1:56567 says: [PRIVATE][obrian][@badman]: bonsoir
le problème majeur se trouve ici pour spyderman qui n'est pas censé etre le destinataire du message privé et qui l'a reçu en privé .
127.0.0.1:56567 says: [PRIVATE][obrian][@badman]: bonsoir.
je compte votre aide la dessus .