修复数据库

This commit is contained in:
DZY 2025-05-31 19:28:43 +08:00
parent 0870a2f923
commit b9b2af664a
3 changed files with 207 additions and 261 deletions

View File

@ -118,6 +118,7 @@ class ChatClient:
return
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(('localhost', 5555))
self.socket.send(json.dumps({
'type': 'login',
@ -131,7 +132,7 @@ class ChatClient:
self.update_ui_state(True)
threading.Thread(target=self.receive_messages, daemon=True).start()
else:
messagebox.showerror("Error", "Login failed")
messagebox.showerror("Error", "Login failed - Invalid username or password")
self.socket.close()
except Exception as e:
messagebox.showerror("Error", f"Connection error: {str(e)}")
@ -154,11 +155,12 @@ class ChatClient:
}).encode('utf-8'))
response = json.loads(temp_socket.recv(1024).decode('utf-8'))
if response['type'] == 'register_success':
messagebox.showinfo("Success", "Registration successful")
else:
messagebox.showerror("Error", "Registration failed - username may be taken")
temp_socket.close()
if response['type'] == 'register_success':
messagebox.showinfo("Success", "Registration successful. Please login now.")
else:
messagebox.showerror("Error", "Registration failed - username may be taken or invalid")
except Exception as e:
messagebox.showerror("Error", f"Connection error: {str(e)}")
@ -195,6 +197,10 @@ class ChatClient:
msg['is_group'],
msg['timestamp']
)
elif data['type'] == 'server_shutdown':
messagebox.showinfo("Server", "Server is shutting down")
self.on_closing()
break
except Exception as e:
print(f"Error receiving message: {e}")
break
@ -202,7 +208,7 @@ class ChatClient:
def display_message(self, sender, receiver, message, is_group, timestamp=None):
timestamp = timestamp or datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if (is_group and receiver == self.current_chat and sender != self.current_user) or \
if (is_group and receiver == self.current_chat) or \
(not is_group and ((sender == self.current_chat and receiver == self.current_user) or \
(sender == self.current_user and receiver == self.current_chat))):
@ -259,6 +265,9 @@ class ChatClient:
self.message_entry.delete(0, tk.END)
def show_create_group_dialog(self):
if not self.current_user:
return
dialog = tk.Toplevel(self.root)
dialog.title("Create Group")
dialog.geometry("300x300")
@ -301,8 +310,11 @@ class ChatClient:
ttk.Button(button_frame, text="Cancel", command=dialog.destroy).pack(side=tk.RIGHT, padx=(0, 5))
def on_closing(self):
if self.current_user:
if hasattr(self, 'socket') and self.current_user:
try:
self.socket.close()
except:
pass
self.root.destroy()
if __name__ == "__main__":

View File

@ -3,12 +3,14 @@ import threading
import json
import sqlite3
from datetime import datetime
import os
class ChatServer:
def __init__(self, host='0.0.0.0', port=5555):
self.host = host
self.port = port
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((host, port))
self.server.listen()
self.clients = {}
@ -16,258 +18,52 @@ class ChatServer:
self.setup_database()
def setup_database(self):
# 确保数据库文件存在并初始化
db_exists = os.path.exists('chat_server.db')
self.db = sqlite3.connect('chat_server.db', check_same_thread=False)
cursor = self.db.cursor()
# 创建用户表
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
password TEXT
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
)
''')
# 创建消息表
cursor.execute('''
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender TEXT,
receiver TEXT,
message TEXT,
timestamp DATETIME,
is_group INTEGER
sender TEXT NOT NULL,
receiver TEXT NOT NULL,
message TEXT NOT NULL,
timestamp DATETIME NOT NULL,
is_group INTEGER NOT NULL
)
''')
self.db.commit()
def handle_client(self, client, address):
username = None
# 如果是首次创建数据库,添加一个默认管理员用户
if not db_exists:
try:
while True:
message = client.recv(1024).decode('utf-8')
if not message:
break
data = json.loads(message)
if data['type'] == 'login':
username = data['username']
password = data['password']
if self.authenticate_user(username, password):
self.clients[username] = client
self.groups['General'].add(username)
client.send(json.dumps({'type': 'login_success'}).encode('utf-8'))
self.send_user_list()
self.send_group_list(username)
self.send_initial_messages(username)
else:
client.send(json.dumps({'type': 'login_fail'}).encode('utf-8'))
elif data['type'] == 'register':
username = data['username']
password = data['password']
if self.register_user(username, password):
client.send(json.dumps({'type': 'register_success'}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'register_fail'}).encode('utf-8'))
elif data['type'] == 'message':
sender = data['sender']
receiver = data['receiver']
msg = data['message']
is_group = data['is_group']
self.save_message(sender, receiver, msg, is_group)
if is_group:
for member in self.groups.get(receiver, set()):
if member in self.clients and member != sender:
self.clients[member].send(json.dumps({
'type': 'message',
'sender': sender,
'receiver': receiver,
'message': msg,
'is_group': True
}).encode('utf-8'))
else:
if receiver in self.clients:
self.clients[receiver].send(json.dumps({
'type': 'message',
'sender': sender,
'receiver': receiver,
'message': msg,
'is_group': False
}).encode('utf-8'))
elif data['type'] == 'create_group':
group_name = data['group_name']
if group_name not in self.groups:
self.groups[group_name] = set()
for user in data['members']:
if user in self.clients:
self.groups[group_name].add(user)
self.send_group_list_to_all()
# 管理API处理逻辑
elif data['type'] == 'admin_get_users':
cursor = self.db.cursor()
cursor.execute('SELECT id, username FROM users')
users = [{'id': row[0], 'username': row[1]} for row in cursor.fetchall()]
client.send(json.dumps({'type': 'admin_response', 'data': users}).encode('utf-8'))
elif data['type'] == 'admin_create_user':
try:
cursor = self.db.cursor()
cursor.execute('INSERT INTO users (username, password) VALUES (?, ?)',
(data['username'], data['password']))
self.db.commit()
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
('admin', 'admin123'))
print("Created default admin user: admin/admin123")
except sqlite3.IntegrityError:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'Username exists'}).encode('utf-8'))
pass
elif data['type'] == 'admin_delete_user':
cursor = self.db.cursor()
try:
cursor.execute('DELETE FROM messages WHERE sender=? OR receiver=?',
(data['username'], data['username']))
cursor.execute('DELETE FROM users WHERE username=?', (data['username'],))
self.db.commit()
if data['username'] in self.clients:
self.clients[data['username']].close()
del self.clients[data['username']]
for group in self.groups.values():
if data['username'] in group:
group.remove(data['username'])
self.send_user_list()
self.send_group_list_to_all()
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
except Exception as e:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': str(e)}).encode('utf-8'))
elif data['type'] == 'admin_get_messages':
cursor = self.db.cursor()
query = 'SELECT id, sender, receiver, message, timestamp, is_group FROM messages WHERE 1=1'
params = []
if 'sender' in data and data['sender']:
query += ' AND sender=?'
params.append(data['sender'])
if 'receiver' in data and data['receiver']:
query += ' AND receiver=?'
params.append(data['receiver'])
if 'is_group' in data and data['is_group'] is not None:
query += ' AND is_group=?'
params.append(1 if data['is_group'] else 0)
if 'start_time' in data and data['start_time']:
query += ' AND timestamp >= ?'
params.append(data['start_time'])
if 'end_time' in data and data['end_time']:
query += ' AND timestamp <= ?'
params.append(data['end_time'])
query += ' ORDER BY timestamp DESC LIMIT 1000'
cursor.execute(query, params)
messages = []
for row in cursor.fetchall():
messages.append({
'id': row[0],
'sender': row[1],
'receiver': row[2],
'message': row[3],
'timestamp': row[4],
'is_group': bool(row[5])
})
client.send(json.dumps({'type': 'admin_response', 'data': messages}).encode('utf-8'))
elif data['type'] == 'admin_delete_message':
cursor = self.db.cursor()
cursor.execute('DELETE FROM messages WHERE id=?', (data['message_id'],))
self.db.commit()
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
elif data['type'] == 'admin_get_groups':
groups = []
for name, members in self.groups.items():
groups.append({
'name': name,
'members': list(members)
})
client.send(json.dumps({'type': 'admin_response', 'data': groups}).encode('utf-8'))
elif data['type'] == 'admin_create_group':
group_name = data['group_name']
if group_name not in self.groups:
self.groups[group_name] = set()
for user in data['members']:
if user in self.clients or self.user_exists(user):
self.groups[group_name].add(user)
self.send_group_list_to_all()
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'Group already exists'}).encode('utf-8'))
elif data['type'] == 'admin_delete_group':
if data['group_name'] in self.groups:
del self.groups[data['group_name']]
cursor = self.db.cursor()
cursor.execute('DELETE FROM messages WHERE receiver=? AND is_group=1', (data['group_name'],))
self.db.commit()
self.send_group_list_to_all()
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'Group not found'}).encode('utf-8'))
elif data['type'] == 'admin_add_group_member':
if data['group_name'] in self.groups:
if data['username'] in self.clients or self.user_exists(data['username']):
self.groups[data['group_name']].add(data['username'])
if data['username'] in self.clients:
self.send_group_list(data['username'])
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'User not found'}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'Group not found'}).encode('utf-8'))
elif data['type'] == 'admin_remove_group_member':
if data['group_name'] in self.groups and data['username'] in self.groups[data['group_name']]:
self.groups[data['group_name']].remove(data['username'])
if data['username'] in self.clients:
self.send_group_list(data['username'])
client.send(json.dumps({'type': 'admin_response', 'success': True}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'admin_response', 'success': False, 'error': 'Member not in group'}).encode('utf-8'))
elif data['type'] == 'admin_get_server_status':
status = {
'status': 'running',
'users_online': len(self.clients),
'groups': len(self.groups),
'start_time': str(datetime.now())
}
client.send(json.dumps({'type': 'admin_response', 'data': status}).encode('utf-8'))
elif data['type'] == 'admin_restart_server':
client.send(json.dumps({'type': 'admin_response', 'success': True, 'message': 'Restart command received'}).encode('utf-8'))
elif data['type'] == 'admin_shutdown_server':
client.send(json.dumps({'type': 'admin_response', 'success': True, 'message': 'Shutdown command received'}).encode('utf-8'))
threading.Thread(target=self.shutdown).start()
except Exception as e:
print(f"Error handling client: {e}")
finally:
if username and username in self.clients:
del self.clients[username]
for group in self.groups.values():
if username in group:
group.remove(username)
self.send_user_list()
client.close()
def authenticate_user(self, username, password):
cursor = self.db.cursor()
cursor.execute('SELECT * FROM users WHERE username=? AND password=?', (username, password))
return cursor.fetchone() is not None
def register_user(self, username, password):
if not username or not password:
return False
try:
cursor = self.db.cursor()
cursor.execute('INSERT INTO users (username, password) VALUES (?, ?)', (username, password))
@ -287,18 +83,24 @@ class ChatServer:
def send_user_list(self):
user_list = list(self.clients.keys())
for client in self.clients.values():
try:
client.send(json.dumps({
'type': 'user_list',
'users': user_list
}).encode('utf-8'))
except:
pass
def send_group_list(self, username):
group_list = [group for group, members in self.groups.items() if username in members]
if username in self.clients:
try:
self.clients[username].send(json.dumps({
'type': 'group_list',
'groups': group_list
}).encode('utf-8'))
except:
pass
def send_group_list_to_all(self):
for username in self.clients:
@ -308,11 +110,12 @@ class ChatServer:
cursor = self.db.cursor()
cursor.execute('''
SELECT sender, receiver, message, timestamp, is_group FROM messages
WHERE receiver=? OR (is_group=1 AND receiver IN (
SELECT group_name FROM groups WHERE member=?
)) OR sender=?
WHERE receiver=? OR sender=? OR (is_group=1 AND receiver IN (
SELECT name FROM sqlite_master WHERE type='table' AND name='groups'
))
ORDER BY timestamp
''', (username, username, username))
LIMIT 100
''', (username, username))
messages = []
for sender, receiver, message, timestamp, is_group in cursor.fetchall():
@ -325,17 +128,148 @@ class ChatServer:
})
if username in self.clients:
try:
self.clients[username].send(json.dumps({
'type': 'initial_messages',
'messages': messages
}).encode('utf-8'))
except:
pass
def user_exists(self, username):
cursor = self.db.cursor()
cursor.execute('SELECT 1 FROM users WHERE username=?', (username,))
return cursor.fetchone() is not None
def handle_client(self, client, address):
username = None
print(f"New connection from {address}")
try:
while True:
try:
message = client.recv(1024).decode('utf-8')
if not message:
break
data = json.loads(message)
print(f"Received from {address}: {data}")
if data['type'] == 'login':
username = data['username']
password = data['password']
if self.authenticate_user(username, password):
self.clients[username] = client
self.groups['General'].add(username)
client.send(json.dumps({'type': 'login_success'}).encode('utf-8'))
self.send_user_list()
self.send_group_list(username)
self.send_initial_messages(username)
print(f"User {username} logged in successfully")
else:
client.send(json.dumps({'type': 'login_fail', 'reason': 'Invalid username or password'}).encode('utf-8'))
print(f"Login failed for {username}")
elif data['type'] == 'register':
username = data['username']
password = data['password']
if len(username) < 3 or len(password) < 3:
client.send(json.dumps({'type': 'register_fail', 'reason': 'Username and password must be at least 3 characters'}).encode('utf-8'))
elif self.register_user(username, password):
client.send(json.dumps({'type': 'register_success'}).encode('utf-8'))
print(f"New user registered: {username}")
else:
client.send(json.dumps({'type': 'register_fail', 'reason': 'Username already taken'}).encode('utf-8'))
elif data['type'] == 'message':
sender = data['sender']
receiver = data['receiver']
msg = data['message']
is_group = data['is_group']
self.save_message(sender, receiver, msg, is_group)
if is_group:
for member in self.groups.get(receiver, set()):
if member in self.clients and member != sender:
try:
self.clients[member].send(json.dumps({
'type': 'message',
'sender': sender,
'receiver': receiver,
'message': msg,
'is_group': True
}).encode('utf-8'))
except:
pass
else:
if receiver in self.clients:
try:
self.clients[receiver].send(json.dumps({
'type': 'message',
'sender': sender,
'receiver': receiver,
'message': msg,
'is_group': False
}).encode('utf-8'))
except:
pass
elif data['type'] == 'create_group':
group_name = data['group_name']
if group_name not in self.groups:
self.groups[group_name] = set()
for user in data['members']:
if user in self.clients or self.user_exists(user):
self.groups[group_name].add(user)
self.send_group_list_to_all()
client.send(json.dumps({'type': 'group_created', 'group': group_name}).encode('utf-8'))
else:
client.send(json.dumps({'type': 'group_exists', 'group': group_name}).encode('utf-8'))
except json.JSONDecodeError:
print(f"Invalid JSON received from {address}")
break
except ConnectionResetError:
print(f"Connection reset by {address}")
break
except Exception as e:
print(f"Error handling client {address}: {str(e)}")
break
except Exception as e:
print(f"Client handler error for {address}: {str(e)}")
finally:
if username and username in self.clients:
print(f"User {username} disconnected")
del self.clients[username]
for group in self.groups.values():
if username in group:
group.remove(username)
self.send_user_list()
try:
client.close()
except:
pass
def start(self):
print(f"Server started on {self.host}:{self.port}")
print("Database initialized at chat_server.db")
try:
while True:
client, address = self.server.accept()
thread = threading.Thread(target=self.handle_client, args=(client, address))
thread.daemon = True
thread.start()
except KeyboardInterrupt:
print("\nServer is shutting down...")
finally:
for client in self.clients.values():
try:
client.close()
except:
pass
self.server.close()
self.db.close()
print("Server stopped")
if __name__ == "__main__":
server = ChatServer()

View File

@ -2,7 +2,7 @@ from flask import Flask, request, jsonify
import socket
import json
import threading
#from datetime import datetime
from datetime import datetime
app = Flask(__name__)