一.安装python版本:3.6.8
sudo yum install python3
pip3 install websockets
pip3 install asyncio
安全组 里面任意ip都可以访问 A1:9999 A2:9998两个对外的端口
二.python日志服务器代码:监听客户端websocket
import asyncio
import websockets
import os
import traceback
import sys
import locale
from datetime import datetime
尝试修复终端编码
def fix_encoding():
"""尝试修复终端编码问题"""
try:
获取当前编码
current_encoding = locale.getpreferredencoding()
print(f"Current encoding: {current_encoding}")
如果是Windows,尝试设置UTF-8
if sys.platform == "win32":
os.system("chcp 65001 > nul")
设置环境变量
os.environ['PYTHONIOENCODING'] = 'utf-8'
尝试重新设置标准输出编码
if sys.stdout.encoding != 'UTF-8':
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
except Exception as e:
print(f"Warning: Could not fix encoding: {e}")
在main函数开始前调用
fix_encoding()
然后继续你的代码...
open_files = {}
def get_open_file(filename):
"""获取或创建日志文件,确保目录存在"""
log_dir = os.path.dirname(filename)
if log_dir and not os.path.exists(log_dir):
try:
os.makedirs(log_dir, exist_ok=True)
except OSError as e:
print(f"创建日志目录失败: {e}")
return None
if filename in open_files:
return open_files[filename]
else:
try:
open_file = open(filename, 'a', encoding='utf-8')
open_files[filename] = open_file
return open_file
except IOError as e:
print(f"打开日志文件失败: {e}")
return None
def close_open_file(filename):
"""安全关闭日志文件并从缓存中移除"""
if filename in open_files:
try:
open_files[filename].close()
except IOError as e:
print(f"关闭日志文件失败: {e}")
finally:
del open_files[filename]
async def echo(websocket, path):
"""处理WebSocket连接"""
client_ip = websocket.remote_address[0] if websocket.remote_address else "unknown"
print(f"\n=== 新的客户端连接 ===")
print(f"--IP: {client_ip}")
print(f"--path: {path}")
接收客户端发送的文件名前缀(首次消息)
try:
增加超时时间为10秒
print("等待客户端发送前缀信息...")
path_data = await asyncio.wait_for(websocket.recv(), timeout=10.0)
print(f" 收到数据: {repr(path_data)}")
print(f" 数据类型: {type(path_data)}")
print(f" 数据长度: {len(path_data)}")
净化输入,确保文件名安全
path_suffix = path_data.strip()
print(f"--原始前缀: {path_suffix}")
只保留字母、数字、下划线和横线(避免路径注入)
path_suffix = "".join([c for c in path_suffix if c.isalnum() or c in ['_', '-']])
如果净化后为空,使用默认值
if not path_suffix:
path_suffix = "default"
print("前缀为空,使用默认值")
print(f"最终使用的前缀: {path_suffix}")
except asyncio.TimeoutError:
print("等待前缀超时")
path_suffix = "default"
except websockets.exceptions.ConnectionClosed as e:
print(f"连接已关闭: {e.code} - {e.reason}")
return
except Exception as e:
print(f"接收前缀时发生异常: {e}")
traceback.print_exc()
return
生成精确到毫秒的时间戳(格式:年-月-日-时-分-秒-毫秒)
timestr = datetime.now().strftime("%Y-%m-%d-%H-%M-%S-%f")[:-3]
构建日志文件名(格式:log/前缀-时间戳.txt)
file_name = f"tinyou2log/{path_suffix}-{timestr}.txt"
print(f"日志文件: {file_name}")
log_file = get_open_file(file_name)
if not log_file:
print("错误: 无法创建日志文件,连接将关闭")
return
try:
记录连接信息
connect_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
log_file.write(f"[{connect_time}] 客户端 {client_ip} 已连接\n")
log_file.write(f"[{connect_time}] 使用前缀: {path_suffix}\n")
log_file.flush()
接收并记录后续消息
print("等待接收后续消息...")
try:
while True:
message = await websocket.recv()
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
log_entry = f"[{timestamp}] 收到消息: {message}\n"
print(f"收到消息: {message}")
log_file.write(log_entry)
log_file.flush()
except websockets.exceptions.ConnectionClosed:
print("客户端断开连接")
except websockets.exceptions.ConnectionClosedError:
disconnect_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
print(f"客户端 {client_ip} 断开连接")
log_file.write(f"[{disconnect_time}] 客户端 {client_ip} 已断开连接\n")
log_file.flush()
except Exception as e:
print(f"处理客户端时发生错误: {e}")
traceback.print_exc()
finally:
close_open_file(file_name)
print(f"日志文件 {file_name} 已关闭")
print("=== 连接处理结束 ===\n")
async def main():
try:
创建日志目录
os.makedirs("tinyou2log", exist_ok=True)
async with websockets.serve(echo, "0.0.0.0", 9998):
print("=" * 60)
print(" WebSocket 日志服务器启动")
print(" 监听地址: 0.0.0.0:9998")
print(" 日志路径: " + os.path.abspath("tinyou2log"))
print(" 等待客户端连接...")
print("=" * 60)
await asyncio.Future() # 保持服务器运行
except OSError as e:
print(f"服务器启动失败: {e}")
if e.errno == 98:
print("端口9999已被占用,请使用其他端口或停止占用该端口的进程")
if name == "main":
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
except KeyboardInterrupt:
print("\n服务器已停止")
finally:
loop.close()
三.客户端测试
测试1:ws://123.56.30.115:9998
测试2:wss://jhtg.ser01.tjxzhd.com/wstyjh2
<!DOCTYPE html>
<html>
<head>
<title>WebSocket测试</title>
<meta charset="utf-8">
</head>
<body>
<h1>WebSocket连接测试</h1>
<div>
<label>服务器地址:</label>
<input type="text" id="serverUrl" value="wss://jhtg.ser01.tjxzhd.com/wstyjh2" style="width: 400px;">
<button onclick="connect()">连接</button>
<button onclick="disconnect()">断开</button>
<button onclick="sendTest()">发送测试消息</button>
</div>
<div>
<label>消息:</label>
<input type="text" id="message" value="test123456" style="width: 300px;">
<button onclick="sendMessage()">发送</button>
</div>
<div>
<h3>日志:</h3>
<pre id="log" style="border: 1px solid #ccc; padding: 10px; height: 300px; overflow: auto;"></pre>
</div>
<script>
let ws = null;
const log = document.getElementById('log');
function addLog(msg) {
const time = new Date().toLocaleTimeString();
log.textContent += `[{time}\] {msg}\n`;
log.scrollTop = log.scrollHeight;
}
function connect() {
const url = document.getElementById('serverUrl').value;
addLog(`尝试连接到: ${url}`);
ws = new WebSocket(url);
ws.onopen = function(event) {
addLog('连接成功!');
addLog(`readyState: ${ws.readyState}`);
// 立即发送测试消息
ws.send('gandecheng');
};
ws.onmessage = function(event) {
addLog(`收到消息: ${event.data}`);
};
ws.onerror = function(error) {
addLog(`连接错误: ${error}`);
console.error('WebSocket错误:', error);
};
ws.onclose = function(event) {
addLog(`连接关闭 - 代码: {event.code}, 原因: {event.reason}`);
};
}
function disconnect() {
if (ws) {
ws.close(1000, '用户手动断开');
addLog('正在断开连接...');
}
}
function sendMessage() {
if (ws && ws.readyState === WebSocket.OPEN) {
const msg = document.getElementById('message').value;
ws.send(msg);
addLog(`发送: ${msg}`);
} else {
addLog('连接未就绪,无法发送消息');
}
}
function sendTest() {
const testMsg = JSON.stringify({
type: 'test',
timestamp: new Date().toISOString(),
data: '这是一个测试消息'
});
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(testMsg);
addLog(`发送测试消息: ${testMsg}`);
} else {
addLog('连接未就绪');
}
}
// 页面加载时自动连接
window.onload = function() {
addLog('页面加载完成');
// 可选:自动连接
// connect();
};
</script>
</body>
</html>