-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
104 lines (93 loc) · 3.26 KB
/
server.py
File metadata and controls
104 lines (93 loc) · 3.26 KB
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
import socket
import threading
import time
from rich import print
from rich.console import Console
HOST = "0.0.0.0"
PORT = 5555
clients = [] # list of client sockets
nicknames = [] # corresponding nicknames
lock = threading.Lock()
console = Console()
def broadcast(message, sender_socket=None):
"""Send message to all clients except the sender (optional)."""
with lock:
for client in clients[:]:
if client != sender_socket:
try:
client.send(message)
except:
client.close()
remove_client(client)
def broadcast_userlist():
"""Send the current list of nicknames to all clients."""
with lock:
userlist = ",".join(nicknames)
msg = f"##users##{userlist}".encode('utf-8')
for client in clients:
try:
client.send(msg)
except:
client.close()
remove_client(client)
def remove_client(client_socket):
"""Remove a dead client and notify others."""
with lock:
if client_socket in clients:
idx = clients.index(client_socket)
nick = nicknames[idx]
clients.remove(client_socket)
nicknames.pop(idx)
console.print(f"[red]{nick} left the chat[/red]")
broadcast(f"🔴 {nick} left the chat.".encode('utf-8'))
broadcast_userlist() # update everyone's user list
def handle_client(conn, addr):
"""Receive messages from one client."""
try:
nickname = conn.recv(1024).decode('utf-8').strip()
except:
conn.close()
return
with lock:
clients.append(conn)
nicknames.append(nickname)
console.print(f"[green]{nickname} connected from {addr}[/green]")
broadcast(f"🟢 {nickname} joined the chat.".encode('utf-8'))
broadcast_userlist() # send updated user list to everyone
try:
while True:
data = conn.recv(1024)
if not data:
break
message = data.decode('utf-8')
console.print(f"[cyan]{nickname}:[/cyan] {message}")
broadcast(f"{nickname}: {message}".encode('utf-8'), sender_socket=conn)
except (ConnectionResetError, BrokenPipeError):
pass
finally:
remove_client(conn)
conn.close()
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((HOST, PORT))
server.listen()
console.print(f"[green]Server listening on {HOST}:{PORT}[/green]")
try:
while True:
server.settimeout(1.0)
try:
conn, addr = server.accept()
threading.Thread(target=handle_client, args=(conn, addr), daemon=True).start()
except socket.timeout:
continue
except KeyboardInterrupt:
console.print("\n[yellow]Shutting down server...[/yellow]")
finally:
with lock:
for c in clients:
c.close()
server.close()
console.print("[bold red]Server stopped[/bold red]")
if __name__ == "__main__":
main()