-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.py
More file actions
148 lines (123 loc) · 5.2 KB
/
server.py
File metadata and controls
148 lines (123 loc) · 5.2 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
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
136
137
138
139
140
141
142
143
144
145
146
147
148
#server.py
import socket
import threading
import uuid
clients = []
clients_lock = threading.Lock()
chat_history = [] # Store the recent chat messages
history_lock = threading.Lock()
passkey = ""
def generate_passkey():
# Generate a dynamic passkey (can use any method, here using UUID)
return uuid.uuid4().hex[:8] # Generate an 8-character passkey
def handle_client(client_socket, client_address):
global passkey
send_chat_history(client_socket)
try:
# Receive the username and passkey
data = client_socket.recv(4096).decode('utf-8')
username, client_passkey = data.split()
if client_passkey != passkey:
client_socket.send("Invalid passkey! Connection closed.".encode('utf-8'))
client_socket.close()
return
# Broadcast that the user has joined
broadcast(client_socket, f"{username} joined the chat.")
#save_message(f"{username} joined the chat.")
# Handle incoming messages
while True:
message = client_socket.recv(4096).decode('utf-8')
if not message:
break
# Detect file transfer
if message.startswith("[FILE_TRANSFER]"):
handle_file_transfer(client_socket, username)
else:
broadcast(client_socket, f"{username}: {message}")
# save_message(f"{username}: {message}")
except Exception as e:
print(f"Error handling client {client_address}: {e}")
except (ConnectionResetError, socket.error) as e:
print(f"Connection error with {client_address}: {e}")
finally:
disconnect_client(client_socket, username)
# Broadcast function
def broadcast(sender_socket, message):
if message.strip(): # Only process non-empty messages
with clients_lock:
for client in clients:
if client != sender_socket:
try:
client.send(message.encode('utf-8'))
except Exception as e:
print(f"Error broadcasting message: {e}")
save_message(message) # Save only valid messages
def handle_file_transfer(client_socket, username):
try:
# Receive the file name
file_name = client_socket.recv(4096).decode('utf-8')
file_path = f"received_{file_name}"
# Open file for writing
with open(file_path, "wb") as file:
while True:
chunk = client_socket.recv(4096)
if chunk == b"[FILE_END]":
break
file.write(chunk)
# Notify all clients about the received file
broadcast(client_socket, f"{username} sent a file: {file_name}")
save_message(f"{username} sent a file: {file_name}")
except Exception as e:
print(f"Error handling file transfer from {username}: {e}")
# Send chat history to new clients
def send_chat_history(client_socket):
with history_lock: # Ensure thread-safe access to history
if chat_history:
history_data = "[HISTORY]\n" + "\n".join(chat_history)
client_socket.send(history_data.encode('utf-8'))
def save_message(message):
with history_lock:
chat_history.append(message)
if len(chat_history) > 50:
chat_history.pop(0) # Keep only the last 50 messages
def disconnect_client(client_socket, username):
with clients_lock:
if client_socket in clients:
clients.remove(client_socket)
if username: # Ensure the username is valid
departure_message = f"{username} left the chat."
broadcast(None, departure_message)
else:
print("Anonymous user disconnected (no username provided).")
try:
client_socket.close()
except Exception as e:
print(f"Error closing client socket: {e}")
print(f"{username if username else 'A client'} disconnected.")
def start_server():
global passkey
passkey = generate_passkey() # Generate a new passkey when server starts
print(f"Server passkey: {passkey}") # Show passkey for the admin
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 12345)) # Listen on all interfaces
server_socket.listen(5)
ip_address = socket.gethostbyname(socket.gethostname())
print(f"Chat Server started, listening on IP {ip_address}")
try:
while True:
client_socket, client_address = server_socket.accept()
print(f"Connection established with {client_address[0]}:{client_address[1]}")
with clients_lock:
clients.append(client_socket)
client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address), daemon=True)
client_thread.start()
except KeyboardInterrupt:
print("Shutting down server...")
finally:
server_socket.close()
# Ensure to close all client connections before exiting
with clients_lock:
for client in clients:
client.close()
if __name__ == "__main__":
start_server()