-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathszerver-gui.py
135 lines (113 loc) · 8.65 KB
/
szerver-gui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import socket # A socket modul biztosítja a hálózati kommunikációhoz szükséges funkciókat.
import threading # A threading modul lehetővé teszi a párhuzamos szálak futtatását.
import tkinter as tk # A tkinter modul az egyszerű grafikus felhasználói felület (GUI) létrehozására szolgál.
from tkinter.scrolledtext import ScrolledText # A görgethető szövegmező widget importálása.
# Szerver beállításai
SZERVER_IP = "0.0.0.0" # A szerver minden hálózati interfészen figyel.
SZERVER_PORT = 12345 # A szerver által használt portszám.
# Egy szótár, amely az aktív klienseket tárolja az azonosítóik és socketjeik alapján.
kliensek = {}
class SzerverGUI:
def __init__(self, mester): # Az osztály inicializálása.
"""GUI inicializálása."""
self.mester = mester # A tkinter főablak referenciája.
self.mester.title("Chat Szerver") # Az ablak címe.
# Üzenetfolyam megjelenítése
self.uzenet_mezo = ScrolledText(mester, state='disabled', wrap='word') # Görgethető szövegmező.
self.uzenet_mezo.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) # A szövegmező elhelyezése.
# Felhasználók listája
self.felhasznalo_lista = tk.Listbox(mester, height=10, width=50) # Felhasználók listájának widgetje.
self.felhasznalo_lista.pack(padx=10, pady=5, side=tk.LEFT, fill=tk.Y) # A lista elhelyezése.
# Kirúgás gomb
self.kirugas_gomb = tk.Button(mester, text="Felhasználó kirúgása", command=self.kirugas) # Kirúgás gomb.
self.kirugas_gomb.pack(padx=10, pady=5, side=tk.LEFT) # A gomb elhelyezése.
def frissit_uzenetek(self, uzenet): # Az üzenetek frissítésére szolgáló metódus.
"""Üzenetek megjelenítése a szövegmezőben."""
self.uzenet_mezo.configure(state='normal') # Írás engedélyezése.
self.uzenet_mezo.insert(tk.END, f"{uzenet}\n") # Üzenet hozzáadása.
self.uzenet_mezo.configure(state='disabled') # Írásvédetté tétele.
self.uzenet_mezo.yview(tk.END) # Görgetés az utolsó üzenetre.
def frissit_felhasznalok(self): # A felhasználók listájának frissítésére szolgáló metódus.
"""Felhasználók listájának frissítése a GUI-ban."""
self.felhasznalo_lista.delete(0, tk.END) # A lista kiürítése.
for azonosito, (socket, cim) in kliensek.items(): # Végigmegy az aktív klienseken.
self.felhasznalo_lista.insert(tk.END, f"{cim[0]}:{cim[1]} {azonosito}") # Felhasználó hozzáadása a listához.
def felhasznalo_lista_kuldes(self): # Új metódus a terminálos szerver logikájával.
"""Aktív felhasználók listájának kiküldése minden csatlakozott kliensnek."""
felhasznalo_lista = list(kliensek.keys()) # Az aktív felhasználók listájának kinyerése.
for socket, _ in kliensek.values(): # Az összes kliens socketjén iterálás.
try:
socket.send(f"USERS:{','.join(felhasznalo_lista)}\n".encode("utf-8")) # A lista elküldése.
except Exception as hiba: # Hibakezelés a küldés során.
self.frissit_uzenetek(f"Hiba a felhasználók listájának küldésekor: {hiba}") # Hiba naplózása.
def kirugas(self): # A kijelölt felhasználó kirúgására szolgáló metódus.
"""Felhasználó kirúgása a szerverről."""
kijelolt = self.felhasznalo_lista.curselection() # Kiválasztott sor lekérdezése.
if kijelolt: # Ha van kiválasztott sor.
adatok = self.felhasznalo_lista.get(kijelolt[0]) # A kiválasztott sor adatai.
ip, _, azonosito = adatok.partition(" ") # Az IP és az azonosító szétválasztása.
if azonosito in kliensek: # Ha az azonosító létezik.
socket, _ = kliensek.pop(azonosito) # A felhasználó eltávolítása a szótárból.
try:
socket.shutdown(socket.SHUT_RDWR) # A socket lezárása.
socket.close() # A socket bezárása.
except Exception as hiba: # Hibakezelés a socket bezárásánál.
self.frissit_uzenetek(f"Hiba a felhasználó eltávolításakor: {hiba}") # Hiba naplózása.
self.felhasznalo_lista_kuldes() # Friss lista elküldése.
self.frissit_felhasznalok() # A GUI lista frissítése.
self.frissit_uzenetek(f"Felhasználó kirúgva: {azonosito} ({ip})") # Naplózás.
def kezeles(kliens_socket, kliens_cim, gui): # Egy kliens kapcsolatának kezelése.
"""Kliens kapcsolat kezelése."""
print(f"Kapcsolódott: {kliens_cim}") # Az új kliens naplózása.
kliens_azonosito = None # Az azonosító tárolására szolgáló változó.
try: # Hibakezelés a klienssel való munkavégzéshez.
while True: # Végtelen ciklus az üzenetek fogadására.
uzenet = kliens_socket.recv(1024).decode("utf-8") # Üzenet fogadása.
if not uzenet: # Ha nincs több adat, megszakítjuk a kapcsolatot.
break
if uzenet.startswith("ID:"): # Az azonosító beállítása.
kliens_azonosito = uzenet.split(":", 1)[1] # Az azonosító kinyerése.
kliensek[kliens_azonosito] = (kliens_socket, kliens_cim) # Az azonosító mentése.
kliens_socket.send(f"Üdvözlünk, {kliens_azonosito}!\n".encode("utf-8")) # Üdvözlő üzenet küldése.
gui.frissit_felhasznalok() # A GUI lista frissítése.
gui.felhasznalo_lista_kuldes() # Felhasználói lista elküldése.
elif uzenet.startswith("SEND:"): # Ha az üzenet másik kliensnek szól.
_, cel_azonosito, uzenet_szoveg = uzenet.split(":", 2) # Az üzenet feldolgozása.
if cel_azonosito in kliensek: # Ha létezik a célzott kliens.
kliensek[cel_azonosito][0].send(f"MSG:{kliens_azonosito}:{uzenet_szoveg}\n".encode("utf-8")) # Üzenet küldése.
gui.frissit_uzenetek(f"Feladó: {kliens_azonosito}, fogadó: {cel_azonosito}, üzenet: {uzenet_szoveg}") # Naplózás.
elif uzenet.startswith("ALL:"): # Ha az üzenet minden kliensnek szól.
uzenet_szoveg = uzenet.split(":", 1)[1] # Az üzenet szövegének kinyerése.
for masik_azonosito, (masik_socket, _) in kliensek.items(): # Minden kliens iterációja.
if masik_azonosito != kliens_azonosito: # Ne küldje vissza a küldőnek.
masik_socket.send(f"MSG:{kliens_azonosito} (ALL):{uzenet_szoveg}\n".encode("utf-8")) # Broadcast üzenet.
gui.frissit_uzenetek(f"Feladó: {kliens_azonosito}, üzenet mindenkinek: {uzenet_szoveg}") # Naplózás.
except Exception as hiba: # Hibakezelés.
gui.frissit_uzenetek(f"Hiba: {hiba}") # Hiba naplózása.
finally: # A kapcsolat lezárása.
if kliens_azonosito: # Ha van azonosító.
kliensek.pop(kliens_azonosito, None) # Az azonosító eltávolítása.
gui.frissit_felhasznalok() # GUI lista frissítése.
gui.felhasznalo_lista_kuldes() # Lista elküldése.
kliens_socket.close() # Kapcsolat bontása.
def main(): # A szerver fő futtatási függvénye.
"""Fő szerver függvény."""
szerver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP socket létrehozása.
szerver.settimeout(None) # Nincs timeout
szerver.bind((SZERVER_IP, SZERVER_PORT)) # A socket kötése a szerver IP-jéhez és portjához.
szerver.listen(5) # Maximum 5 várakozó kapcsolat.
print(f"Szerver fut: {SZERVER_IP}:{SZERVER_PORT}") # A szerver indulásának naplózása.
foablak = tk.Tk() # Tkinter főablak létrehozása.
gui = SzerverGUI(foablak) # A GUI példányosítása.
def kapcsolat_figyelo(): # Új kapcsolatok fogadását végző függvény.
"""Új kapcsolatok figyelése."""
while True: # Végtelen ciklus.
kliens_socket, kliens_cim = szerver.accept() # Új kliens kapcsolat elfogadása.
gui.frissit_uzenetek(f"Új kapcsolat: {kliens_cim[0]}:{kliens_cim[1]}") # Kapcsolódási információk megjelenítése.
szal = threading.Thread(target=kezeles, args=(kliens_socket, kliens_cim, gui)) # Új szál létrehozása a kliens kezelésére.
szal.start() # A szál elindítása.
kapcsolat_szal = threading.Thread(target=kapcsolat_figyelo, daemon=True) # Szál indítása a kapcsolatok figyelésére.
kapcsolat_szal.start()
foablak.mainloop() # A Tkinter eseménykezelő ciklus indítása.
if __name__ == "__main__":
main() # A szerver indítása, ha a fájl közvetlenül futtatva lett.