linux上面写python3日志服务器

一.安装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>

相关推荐
yBmZlQzJ2 小时前
免费内网穿透-端口转发配置介绍
运维·经验分享·docker·容器·1024程序员节
JH30732 小时前
docker 新手入门:10分钟搞定基础使用
运维·docker·容器
Rose sait3 小时前
【环境配置】Linux配置虚拟环境pytorch
linux·人工智能·python
小卒过河01043 小时前
使用apache nifi 从数据库文件表路径拉取远程文件至远程服务器目的地址
运维·服务器·数据库
土星云SaturnCloud3 小时前
液冷“内卷”:在局部优化与系统重构之间,寻找第三条路
服务器·人工智能·ai·计算机外设
Empty_7773 小时前
DevOps理念
运维·devops
叶之香3 小时前
CentOS/RHEL 7、8安装exfat和ntfs文件系统
linux·运维·centos
一世琉璃白_Y4 小时前
pg配置国内数据源安装
linux·python·postgresql·centos