我不到啊
This commit is contained in:
parent
23dc75285f
commit
e1862126e8
155
CS3.1.py
155
CS3.1.py
@ -6,13 +6,21 @@ import socket
|
|||||||
import secrets
|
import secrets
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
socket_server = socket.socket()
|
socket_server = socket.socket()
|
||||||
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
# 修改数据结构:使用用户名作为主键
|
# 修改数据结构:使用用户名作为主键
|
||||||
active_connections = {} # {username: {'conn': conn, 'ip': ip}}
|
active_connections = {} # {username: {'conn': conn, 'ip': ip, 'last_active': timestamp}}
|
||||||
chat_connections = [] # 所有活跃连接列表
|
chat_connections = [] # 所有活跃连接列表
|
||||||
tokens = {} # 令牌管理
|
tokens = {} # 令牌管理
|
||||||
|
|
||||||
@ -49,7 +57,6 @@ def register_user(usr, pwd, avatar="default_avatar.png"):
|
|||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
try:
|
try:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# 添加avatar字段
|
|
||||||
cursor.execute("INSERT INTO users (name, passwd, avatar) VALUES (?, ?, ?)",
|
cursor.execute("INSERT INTO users (name, passwd, avatar) VALUES (?, ?, ?)",
|
||||||
(usr, pwd, avatar))
|
(usr, pwd, avatar))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@ -78,9 +85,8 @@ def register1():
|
|||||||
vl = request.get_json()
|
vl = request.get_json()
|
||||||
usr = vl.get('username')
|
usr = vl.get('username')
|
||||||
pwd = vl.get('password')
|
pwd = vl.get('password')
|
||||||
avatar = vl.get('avatar', 'default_avatar.png') # 获取头像
|
avatar = vl.get('avatar', 'default_avatar.png')
|
||||||
|
|
||||||
# 头像验证
|
|
||||||
if avatar and not (avatar.endswith('.png') or avatar.endswith('.jpg')):
|
if avatar and not (avatar.endswith('.png') or avatar.endswith('.jpg')):
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"type": "register_0",
|
"type": "register_0",
|
||||||
@ -101,11 +107,24 @@ def login():
|
|||||||
|
|
||||||
# 检查账号是否已登录
|
# 检查账号是否已登录
|
||||||
if username in active_connections:
|
if username in active_connections:
|
||||||
return jsonify({
|
# 检查连接是否仍然活跃
|
||||||
"type": "login_0",
|
conn_info = active_connections[username]
|
||||||
"status": "error",
|
try:
|
||||||
"message": "Account already logged in"
|
# 发送测试消息检查连接是否有效
|
||||||
}), 409 # 冲突状态码
|
conn_info['conn'].sendall(json.dumps({"type": "ping"}).encode('utf-8'))
|
||||||
|
logger.info(f"用户 {username} 的连接仍然活跃")
|
||||||
|
return jsonify({
|
||||||
|
"type": "login_0",
|
||||||
|
"status": "error",
|
||||||
|
"message": "Account already logged in"
|
||||||
|
}), 409
|
||||||
|
except:
|
||||||
|
# 连接已失效,清理旧连接
|
||||||
|
logger.warning(f"清理无效连接: {username}")
|
||||||
|
if username in active_connections:
|
||||||
|
del active_connections[username]
|
||||||
|
if conn_info['conn'] in chat_connections:
|
||||||
|
chat_connections.remove(conn_info['conn'])
|
||||||
|
|
||||||
if isuserxist(username) and ispsswdright(username, data['password']):
|
if isuserxist(username) and ispsswdright(username, data['password']):
|
||||||
token = generate_token(username)
|
token = generate_token(username)
|
||||||
@ -114,7 +133,7 @@ def login():
|
|||||||
"type": "login_1",
|
"type": "login_1",
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"token": token,
|
"token": token,
|
||||||
"avatar": avatar # 返回头像
|
"avatar": avatar
|
||||||
})
|
})
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"type": "login_0",
|
"type": "login_0",
|
||||||
@ -139,19 +158,20 @@ def chat():
|
|||||||
"type": "chat",
|
"type": "chat",
|
||||||
"user": username,
|
"user": username,
|
||||||
"message": data['message'],
|
"message": data['message'],
|
||||||
"avatar": get_avatar(username) # 添加头像信息
|
"avatar": get_avatar(username)
|
||||||
}
|
}
|
||||||
broadcast_message(message)
|
broadcast_message(message)
|
||||||
return jsonify({"type": "chat", "status": "success"})
|
return jsonify({"type": "chat", "status": "success"})
|
||||||
|
|
||||||
def broadcast_message(message, sender=None):
|
def broadcast_message(message, sender=None):
|
||||||
for conn in chat_connections:
|
for conn in chat_connections[:]: # 使用副本迭代
|
||||||
try:
|
try:
|
||||||
conn.sendall(json.dumps(message).encode('utf-8'))
|
conn.sendall(json.dumps(message).encode('utf-8'))
|
||||||
except:
|
except:
|
||||||
# 连接异常时移除
|
# 连接异常时移除
|
||||||
for uname, info in list(active_connections.items()):
|
for uname, info in list(active_connections.items()):
|
||||||
if info['conn'] == conn:
|
if info['conn'] == conn:
|
||||||
|
logger.warning(f"广播时移除无效连接: {uname}")
|
||||||
del active_connections[uname]
|
del active_connections[uname]
|
||||||
break
|
break
|
||||||
if conn in chat_connections:
|
if conn in chat_connections:
|
||||||
@ -170,26 +190,31 @@ def handle_socket_message(data, addr, conn):
|
|||||||
username = data['username']
|
username = data['username']
|
||||||
password = data['password']
|
password = data['password']
|
||||||
|
|
||||||
# 检查账号是否已登录
|
# 检查账号是否已登录且连接有效
|
||||||
if username in active_connections:
|
if username in active_connections:
|
||||||
response = {
|
conn_info = active_connections[username]
|
||||||
"type": "login_0",
|
try:
|
||||||
"status": "error",
|
# 测试连接是否仍然有效
|
||||||
"message": "Account already logged in"
|
conn_info['conn'].sendall(json.dumps({"type": "ping"}).encode('utf-8'))
|
||||||
}
|
logger.info(f"用户 {username} 尝试登录但已有活跃连接")
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
response = {
|
||||||
return response
|
"type": "login_0",
|
||||||
|
"status": "error",
|
||||||
|
"message": "Account already logged in"
|
||||||
|
}
|
||||||
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
|
return response
|
||||||
|
except:
|
||||||
|
# 连接已失效,清理旧连接
|
||||||
|
logger.warning(f"清理无效连接后允许登录: {username}")
|
||||||
|
if username in active_connections:
|
||||||
|
del active_connections[username]
|
||||||
|
if conn_info['conn'] in chat_connections:
|
||||||
|
chat_connections.remove(conn_info['conn'])
|
||||||
|
|
||||||
if isuserxist(username) and ispsswdright(username, password):
|
if isuserxist(username) and ispsswdright(username, password):
|
||||||
# 移除旧连接(如果存在)
|
|
||||||
if username in active_connections:
|
|
||||||
old_conn = active_connections[username]['conn']
|
|
||||||
if old_conn in chat_connections:
|
|
||||||
chat_connections.remove(old_conn)
|
|
||||||
del active_connections[username]
|
|
||||||
|
|
||||||
# 添加新连接
|
# 添加新连接
|
||||||
active_connections[username] = {'conn': conn, 'ip': addr[0]}
|
active_connections[username] = {'conn': conn, 'ip': addr[0], 'last_active': time.time()}
|
||||||
if conn not in chat_connections:
|
if conn not in chat_connections:
|
||||||
chat_connections.append(conn)
|
chat_connections.append(conn)
|
||||||
|
|
||||||
@ -201,9 +226,10 @@ def handle_socket_message(data, addr, conn):
|
|||||||
"message": "Login successful",
|
"message": "Login successful",
|
||||||
"token": token,
|
"token": token,
|
||||||
"username": username,
|
"username": username,
|
||||||
"avatar": avatar # 返回头像
|
"avatar": avatar
|
||||||
}
|
}
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
|
logger.info(f"用户 {username} 登录成功")
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
response = {
|
response = {
|
||||||
@ -244,33 +270,81 @@ def handle_socket_message(data, addr, conn):
|
|||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
# 更新最后活跃时间
|
||||||
|
active_connections[username]['last_active'] = time.time()
|
||||||
|
|
||||||
message = {
|
message = {
|
||||||
"type": "chat",
|
"type": "chat",
|
||||||
"user": username,
|
"user": username,
|
||||||
"message": data['message'],
|
"message": data['message'],
|
||||||
"avatar": get_avatar(username) # 添加头像
|
"avatar": get_avatar(username)
|
||||||
}
|
}
|
||||||
broadcast_message(message)
|
broadcast_message(message)
|
||||||
# 返回成功响应
|
|
||||||
response = {"type": "chat", "status": "success"}
|
response = {"type": "chat", "status": "success"}
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
elif action == 'heartbeat':
|
||||||
|
# 心跳检测
|
||||||
|
token = data.get('token')
|
||||||
|
if token:
|
||||||
|
username = validate_token(token)
|
||||||
|
if username and username in active_connections:
|
||||||
|
# 更新最后活跃时间
|
||||||
|
active_connections[username]['last_active'] = time.time()
|
||||||
|
response = {"type": "heartbeat", "status": "success"}
|
||||||
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
|
return response
|
||||||
|
return {"type": "heartbeat", "status": "error"}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logger.error(f"处理消息时出错: {str(e)}")
|
||||||
response = {
|
response = {
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": str(e)
|
"message": str(e)
|
||||||
}
|
}
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
try:
|
||||||
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def check_inactive_connections():
|
||||||
|
"""定期检查不活跃的连接并清理"""
|
||||||
|
while True:
|
||||||
|
time.sleep(60) # 每分钟检查一次
|
||||||
|
current_time = time.time()
|
||||||
|
inactive_users = []
|
||||||
|
|
||||||
|
for username, info in list(active_connections.items()):
|
||||||
|
# 5分钟无活动视为不活跃
|
||||||
|
if current_time - info['last_active'] > 300:
|
||||||
|
logger.warning(f"检测到不活跃用户: {username}, 最后活跃: {current_time - info['last_active']}秒前")
|
||||||
|
inactive_users.append(username)
|
||||||
|
|
||||||
|
for username in inactive_users:
|
||||||
|
info = active_connections[username]
|
||||||
|
try:
|
||||||
|
info['conn'].close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if username in active_connections:
|
||||||
|
del active_connections[username]
|
||||||
|
if info['conn'] in chat_connections:
|
||||||
|
chat_connections.remove(info['conn'])
|
||||||
|
logger.info(f"已清理不活跃用户: {username}")
|
||||||
|
|
||||||
def run_socket_server():
|
def run_socket_server():
|
||||||
socket_server.bind(("localhost", 8889))
|
socket_server.bind(("0.0.0.0", 8889))
|
||||||
socket_server.listen()
|
socket_server.listen()
|
||||||
print("Socket server running on port 8889")
|
logger.info("Socket server running on port 8889")
|
||||||
|
|
||||||
|
# 启动连接检查线程
|
||||||
|
threading.Thread(target=check_inactive_connections, daemon=True).start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
conn, addr = socket_server.accept()
|
conn, addr = socket_server.accept()
|
||||||
print(f"Socket client connected: {addr}")
|
logger.info(f"Socket client connected: {addr}")
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
data = conn.recv(1024)
|
data = conn.recv(1024)
|
||||||
@ -278,7 +352,6 @@ def run_socket_server():
|
|||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 尝试解码为UTF-8,忽略错误字符
|
|
||||||
decoded_data = data.decode('utf-8', errors='ignore')
|
decoded_data = data.decode('utf-8', errors='ignore')
|
||||||
json_data = json.loads(decoded_data)
|
json_data = json.loads(decoded_data)
|
||||||
response = handle_socket_message(json_data, addr, conn)
|
response = handle_socket_message(json_data, addr, conn)
|
||||||
@ -290,6 +363,7 @@ def run_socket_server():
|
|||||||
}
|
}
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logger.error(f"处理数据时出错: {str(e)}")
|
||||||
response = {
|
response = {
|
||||||
"type": "error",
|
"type": "error",
|
||||||
"status": "error",
|
"status": "error",
|
||||||
@ -297,13 +371,13 @@ def run_socket_server():
|
|||||||
}
|
}
|
||||||
conn.sendall(json.dumps(response).encode('utf-8'))
|
conn.sendall(json.dumps(response).encode('utf-8'))
|
||||||
except (ConnectionResetError, BrokenPipeError):
|
except (ConnectionResetError, BrokenPipeError):
|
||||||
print(f"Client {addr} disconnected abruptly")
|
logger.warning(f"Client {addr} disconnected abruptly")
|
||||||
finally:
|
finally:
|
||||||
# 清理断开的连接
|
# 清理断开的连接
|
||||||
for username, info in list(active_connections.items()):
|
for username, info in list(active_connections.items()):
|
||||||
if info['conn'] == conn:
|
if info['conn'] == conn:
|
||||||
del active_connections[username]
|
del active_connections[username]
|
||||||
print(f"User {username} disconnected")
|
logger.info(f"用户 {username} 断开连接")
|
||||||
break
|
break
|
||||||
|
|
||||||
if conn in chat_connections:
|
if conn in chat_connections:
|
||||||
@ -313,14 +387,13 @@ def run_socket_server():
|
|||||||
conn.close()
|
conn.close()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
print(f"Connection closed for {addr}")
|
logger.info(f"Connection closed for {addr}")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
with get_db_connection() as conn:
|
with get_db_connection() as conn:
|
||||||
# 添加avatar字段
|
|
||||||
conn.execute('''CREATE TABLE IF NOT EXISTS users
|
conn.execute('''CREATE TABLE IF NOT EXISTS users
|
||||||
(name TEXT PRIMARY KEY,
|
(name TEXT PRIMARY KEY,
|
||||||
passwd TEXT,
|
passwd TEXT,
|
||||||
avatar TEXT DEFAULT 'default_avatar.png')''')
|
avatar TEXT DEFAULT 'default_avatar.png')''')
|
||||||
threading.Thread(target=run_socket_server, daemon=True).start()
|
threading.Thread(target=run_socket_server, daemon=True).start()
|
||||||
app.run(port=5001)
|
app.run(port=5001, host='0.0.0.0')
|
Loading…
x
Reference in New Issue
Block a user