feat:测试验证
This commit is contained in:
57
.editorconfig
Normal file
57
.editorconfig
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# 顶级配置文件
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 所有文件
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Python 文件
|
||||||
|
[*.py]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# JSON 文件
|
||||||
|
[*.json]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Markdown 文件
|
||||||
|
[*.md]
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
# YAML 文件
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# JavaScript/TypeScript 文件
|
||||||
|
[*.{js,ts,jsx,tsx}]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# HTML/CSS 文件
|
||||||
|
[*.{html,css}]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Batch 文件 (Windows)
|
||||||
|
[*.bat]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = crlf
|
||||||
|
|
||||||
|
# Shell 脚本
|
||||||
|
[*.sh]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
24
.vscode/settings.json
vendored
24
.vscode/settings.json
vendored
@@ -1,3 +1,25 @@
|
|||||||
{
|
{
|
||||||
"files.autoGuessEncoding": true
|
"files.autoGuessEncoding": false,
|
||||||
|
"files.encoding": "utf8",
|
||||||
|
"files.eol": "\n",
|
||||||
|
"[python]": {
|
||||||
|
"files.encoding": "utf8",
|
||||||
|
"files.eol": "\n"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"files.encoding": "utf8"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"files.encoding": "utf8"
|
||||||
|
},
|
||||||
|
"[html]": {
|
||||||
|
"files.encoding": "utf8"
|
||||||
|
},
|
||||||
|
"[css]": {
|
||||||
|
"files.encoding": "utf8"
|
||||||
|
},
|
||||||
|
"[markdown]": {
|
||||||
|
"files.encoding": "utf8"
|
||||||
|
},
|
||||||
|
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||||
}
|
}
|
||||||
|
|||||||
83
UTF8_ENCODING_STANDARD.md
Normal file
83
UTF8_ENCODING_STANDARD.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# UTF-8 编码规范
|
||||||
|
|
||||||
|
## 项目编码标准
|
||||||
|
|
||||||
|
本项目所有文件必须使用 **UTF-8** 编码格式,以确保中文和特殊字符的正确显示和处理。
|
||||||
|
|
||||||
|
## 文件编码要求
|
||||||
|
|
||||||
|
### 1. Python 文件
|
||||||
|
- **必须** 在文件开头添加编码声明:
|
||||||
|
```python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
```
|
||||||
|
或
|
||||||
|
```python
|
||||||
|
# coding: utf-8
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 文件保存
|
||||||
|
- 所有文件保存时使用 **UTF-8** 编码(无BOM)
|
||||||
|
- 禁止使用 GBK、GB2312 等其他编码格式
|
||||||
|
|
||||||
|
### 3. 文件读取/写入
|
||||||
|
- 所有文件操作必须明确指定 `encoding='utf-8'`:
|
||||||
|
```python
|
||||||
|
with open('file.txt', 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
with open('file.txt', 'w', encoding='utf-8') as f:
|
||||||
|
f.write(content)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cursor/VS Code 配置
|
||||||
|
|
||||||
|
项目已配置 `.vscode/settings.json`,确保:
|
||||||
|
- 默认文件编码:UTF-8
|
||||||
|
- 自动检测编码:禁用(避免误判)
|
||||||
|
- 文件行尾:LF(Unix风格)
|
||||||
|
|
||||||
|
## 控制台输出
|
||||||
|
|
||||||
|
### Windows 系统
|
||||||
|
在 Python 脚本中,需要设置标准输出编码:
|
||||||
|
```python
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||||
|
```
|
||||||
|
|
||||||
|
## 检查脚本
|
||||||
|
|
||||||
|
使用 `check_encoding.py` 脚本检查所有文件的编码格式:
|
||||||
|
```bash
|
||||||
|
python check_encoding.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 1. 控制台输出乱码
|
||||||
|
- 确保文件以 UTF-8 保存
|
||||||
|
- 在脚本开头设置标准输出编码
|
||||||
|
- Windows 系统运行 `chcp 65001` 设置控制台代码页
|
||||||
|
|
||||||
|
### 2. 文件读取乱码
|
||||||
|
- 检查文件实际编码(可用 `check_encoding.py`)
|
||||||
|
- 确保使用 `encoding='utf-8'` 参数
|
||||||
|
|
||||||
|
### 3. 文件保存乱码
|
||||||
|
- 检查编辑器编码设置
|
||||||
|
- 确保 Cursor/VS Code 设置为 UTF-8
|
||||||
|
|
||||||
|
## 验证清单
|
||||||
|
|
||||||
|
创建新文件时,请确认:
|
||||||
|
- [ ] 文件以 UTF-8 编码保存
|
||||||
|
- [ ] Python 文件包含编码声明
|
||||||
|
- [ ] 文件读写操作指定 `encoding='utf-8'`
|
||||||
|
- [ ] 控制台输出脚本设置了 UTF-8 编码
|
||||||
|
- [ ] 测试输出中文显示正常
|
||||||
|
|
||||||
157
check_encoding.py
Normal file
157
check_encoding.py
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
文件编码检查工具
|
||||||
|
检查项目中所有文件是否使用UTF-8编码
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import chardet
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def check_file_encoding(file_path: Path) -> dict:
|
||||||
|
"""检查文件编码"""
|
||||||
|
try:
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
raw_data = f.read()
|
||||||
|
result = chardet.detect(raw_data)
|
||||||
|
encoding = result.get('encoding', 'unknown')
|
||||||
|
confidence = result.get('confidence', 0)
|
||||||
|
|
||||||
|
# 检查文件是否有BOM
|
||||||
|
has_bom = False
|
||||||
|
if raw_data.startswith(b'\xef\xbb\xbf'):
|
||||||
|
has_bom = True
|
||||||
|
encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
return {
|
||||||
|
'file': str(file_path),
|
||||||
|
'encoding': encoding,
|
||||||
|
'confidence': confidence,
|
||||||
|
'has_bom': has_bom,
|
||||||
|
'is_utf8': encoding.lower() in ['utf-8', 'utf-8-sig', 'ascii'],
|
||||||
|
'size': len(raw_data)
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {
|
||||||
|
'file': str(file_path),
|
||||||
|
'error': str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_python_file_header(file_path: Path) -> bool:
|
||||||
|
"""检查Python文件是否有编码声明"""
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
first_lines = [f.readline() for _ in range(3)]
|
||||||
|
for line in first_lines:
|
||||||
|
if 'coding' in line.lower() or 'encoding' in line.lower():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
|
||||||
|
# 需要检查的文件扩展名
|
||||||
|
check_extensions = {'.py', '.json', '.md', '.txt', '.html', '.css', '.js', '.sql', '.bat', '.sh'}
|
||||||
|
|
||||||
|
# 排除的目录
|
||||||
|
exclude_dirs = {'.git', '.venv', '__pycache__', 'node_modules', '.idea', 'logs', 'data', 'dist', 'build'}
|
||||||
|
|
||||||
|
results = []
|
||||||
|
python_files_without_encoding = []
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("文件编码检查工具")
|
||||||
|
print("=" * 80)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 遍历所有文件
|
||||||
|
for root, dirs, files in os.walk(project_root):
|
||||||
|
# 排除指定目录
|
||||||
|
dirs[:] = [d for d in dirs if d not in exclude_dirs]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
file_path = Path(root) / file
|
||||||
|
|
||||||
|
# 只检查指定扩展名的文件
|
||||||
|
if file_path.suffix.lower() not in check_extensions:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 检查编码
|
||||||
|
result = check_file_encoding(file_path)
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
# 检查Python文件的编码声明
|
||||||
|
if file_path.suffix == '.py':
|
||||||
|
if not check_python_file_header(file_path):
|
||||||
|
python_files_without_encoding.append(file_path)
|
||||||
|
|
||||||
|
# 统计结果
|
||||||
|
total_files = len(results)
|
||||||
|
utf8_files = sum(1 for r in results if r.get('is_utf8', False))
|
||||||
|
non_utf8_files = total_files - utf8_files
|
||||||
|
|
||||||
|
print(f"总计检查文件: {total_files}")
|
||||||
|
print(f"UTF-8 编码文件: {utf8_files}")
|
||||||
|
print(f"非 UTF-8 编码文件: {non_utf8_files}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 显示非UTF-8文件
|
||||||
|
if non_utf8_files > 0:
|
||||||
|
print("=" * 80)
|
||||||
|
print("⚠️ 非 UTF-8 编码文件:")
|
||||||
|
print("=" * 80)
|
||||||
|
for result in results:
|
||||||
|
if not result.get('is_utf8', False) and 'error' not in result:
|
||||||
|
print(f" {result['file']}")
|
||||||
|
print(f" 编码: {result['encoding']} (置信度: {result['confidence']:.2%})")
|
||||||
|
if result.get('has_bom'):
|
||||||
|
print(f" ⚠️ 包含 BOM")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 显示缺少编码声明的Python文件
|
||||||
|
if python_files_without_encoding:
|
||||||
|
print("=" * 80)
|
||||||
|
print("⚠️ Python 文件缺少编码声明:")
|
||||||
|
print("=" * 80)
|
||||||
|
for file_path in python_files_without_encoding:
|
||||||
|
print(f" {file_path}")
|
||||||
|
print()
|
||||||
|
print("建议在这些文件开头添加: # -*- coding: utf-8 -*-")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 显示错误
|
||||||
|
errors = [r for r in results if 'error' in r]
|
||||||
|
if errors:
|
||||||
|
print("=" * 80)
|
||||||
|
print("❌ 检查出错的文件:")
|
||||||
|
print("=" * 80)
|
||||||
|
for result in errors:
|
||||||
|
print(f" {result['file']}: {result['error']}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 总结
|
||||||
|
print("=" * 80)
|
||||||
|
if non_utf8_files == 0 and not python_files_without_encoding:
|
||||||
|
print("✅ 所有文件编码检查通过!")
|
||||||
|
else:
|
||||||
|
print("⚠️ 发现编码问题,请根据上述信息修复")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
return non_utf8_files == 0 and not python_files_without_encoding
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
import chardet
|
||||||
|
except ImportError:
|
||||||
|
print("错误: 需要安装 chardet 库")
|
||||||
|
print("运行: pip install chardet")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
success = main()
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"database": {
|
"database": {
|
||||||
"url": "mysql+pymysql://tsp_assistant:password@43.134.68.207/tsp_assistant?charset=utf8mb4",
|
"url": "mysql+pymysql://tsp_assistant:password@jeason.online/tsp_assistant?charset=utf8mb4",
|
||||||
"pool_size": 10,
|
"pool_size": 10,
|
||||||
"max_overflow": 20,
|
"max_overflow": 20,
|
||||||
"pool_timeout": 30,
|
"pool_timeout": 30,
|
||||||
|
|||||||
Binary file not shown.
@@ -10,7 +10,7 @@ class Config:
|
|||||||
ALIBABA_MODEL_NAME = "qwen-plus-latest"
|
ALIBABA_MODEL_NAME = "qwen-plus-latest"
|
||||||
|
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
DATABASE_URL = "mysql+pymysql://tsp_assistant:123456@43.134.68.207/tsp_assistant?charset=utf8mb4"
|
DATABASE_URL = "mysql+pymysql://tsp_assistant:123456@jeason.online/tsp_assistant?charset=utf8mb4"
|
||||||
|
|
||||||
# 知识库配置
|
# 知识库配置
|
||||||
KNOWLEDGE_BASE_PATH = "data/knowledge_base"
|
KNOWLEDGE_BASE_PATH = "data/knowledge_base"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|||||||
@dataclass
|
@dataclass
|
||||||
class DatabaseConfig:
|
class DatabaseConfig:
|
||||||
"""数据库配置"""
|
"""数据库配置"""
|
||||||
url: str = "mysql+pymysql://tsp_assistant:password@43.134.68.207/tsp_assistant?charset=utf8mb4"
|
url: str = "mysql+pymysql://tsp_assistant:password@jeason.online/tsp_assistant?charset=utf8mb4"
|
||||||
pool_size: int = 10
|
pool_size: int = 10
|
||||||
max_overflow: int = 20
|
max_overflow: int = 20
|
||||||
pool_timeout: int = 30
|
pool_timeout: int = 30
|
||||||
|
|||||||
Binary file not shown.
@@ -34,10 +34,13 @@ class DatabaseManager:
|
|||||||
max_overflow=30, # 增加溢出连接数
|
max_overflow=30, # 增加溢出连接数
|
||||||
pool_pre_ping=True,
|
pool_pre_ping=True,
|
||||||
pool_recycle=1800, # 减少回收时间
|
pool_recycle=1800, # 减少回收时间
|
||||||
pool_timeout=10, # 连接超时
|
pool_timeout=30, # 连接池超时(秒)
|
||||||
connect_args={
|
connect_args={
|
||||||
"charset": "utf8mb4",
|
"charset": "utf8mb4",
|
||||||
"autocommit": False
|
"autocommit": False,
|
||||||
|
"connect_timeout": 30, # 连接超时(秒)- 适用于网络延迟较大的情况
|
||||||
|
"read_timeout": 30, # 读取超时(秒)
|
||||||
|
"write_timeout": 30, # 写入超时(秒)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
BIN
src/utils/__pycache__/encoding_helper.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/encoding_helper.cpython-311.pyc
Normal file
Binary file not shown.
66
src/utils/encoding_helper.py
Normal file
66
src/utils/encoding_helper.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
编码辅助工具
|
||||||
|
提供UTF-8编码相关的辅助函数
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def setup_utf8_output():
|
||||||
|
"""设置标准输出为UTF-8编码(Windows系统)"""
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
try:
|
||||||
|
# 设置标准输出编码
|
||||||
|
if hasattr(sys.stdout, 'buffer'):
|
||||||
|
sys.stdout = io.TextIOWrapper(
|
||||||
|
sys.stdout.buffer,
|
||||||
|
encoding='utf-8',
|
||||||
|
errors='replace',
|
||||||
|
line_buffering=True
|
||||||
|
)
|
||||||
|
if hasattr(sys.stderr, 'buffer'):
|
||||||
|
sys.stderr = io.TextIOWrapper(
|
||||||
|
sys.stderr.buffer,
|
||||||
|
encoding='utf-8',
|
||||||
|
errors='replace',
|
||||||
|
line_buffering=True
|
||||||
|
)
|
||||||
|
# 设置控制台代码页为UTF-8
|
||||||
|
os.system('chcp 65001 >nul 2>&1')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def safe_print(*args, **kwargs):
|
||||||
|
"""安全的UTF-8打印函数"""
|
||||||
|
try:
|
||||||
|
print(*args, **kwargs)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
# 如果输出失败,尝试使用ASCII安全版本
|
||||||
|
safe_args = []
|
||||||
|
for arg in args:
|
||||||
|
if isinstance(arg, str):
|
||||||
|
try:
|
||||||
|
safe_args.append(arg.encode('ascii', 'replace').decode('ascii'))
|
||||||
|
except:
|
||||||
|
safe_args.append(repr(arg))
|
||||||
|
else:
|
||||||
|
safe_args.append(arg)
|
||||||
|
print(*safe_args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def read_file_utf8(file_path: str) -> str:
|
||||||
|
"""读取UTF-8编码的文件"""
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def write_file_utf8(file_path: str, content: str):
|
||||||
|
"""写入UTF-8编码的文件"""
|
||||||
|
os.makedirs(os.path.dirname(file_path) if os.path.dirname(file_path) else '.', exist_ok=True)
|
||||||
|
with open(file_path, 'w', encoding='utf-8', newline='\n') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
130
test_mysql_connection.py
Normal file
130
test_mysql_connection.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MySQL连接诊断工具
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
# 添加项目路径以导入编码工具
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
from src.utils.encoding_helper import setup_utf8_output, safe_print
|
||||||
|
setup_utf8_output()
|
||||||
|
except ImportError:
|
||||||
|
# 如果导入失败,使用本地实现
|
||||||
|
import io
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
try:
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||||
|
os.system('chcp 65001 >nul 2>&1')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
safe_print = print
|
||||||
|
|
||||||
|
def test_port(host, port, timeout=5):
|
||||||
|
"""测试端口是否开放"""
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
result = sock.connect_ex((host, port))
|
||||||
|
sock.close()
|
||||||
|
return result == 0
|
||||||
|
except Exception as e:
|
||||||
|
print(f"端口测试异常: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_mysql_connection():
|
||||||
|
"""测试MySQL连接"""
|
||||||
|
# 从配置中提取连接信息
|
||||||
|
db_url = "mysql+pymysql://tsp_assistant:123456@jeason.online/tsp_assistant?charset=utf8mb4"
|
||||||
|
|
||||||
|
parsed = urlparse(db_url.replace("mysql+pymysql://", "http://"))
|
||||||
|
host = parsed.hostname
|
||||||
|
port = parsed.port or 3306
|
||||||
|
|
||||||
|
# 使用安全的UTF-8输出
|
||||||
|
safe_print("=" * 60)
|
||||||
|
safe_print("MySQL连接诊断工具")
|
||||||
|
safe_print("=" * 60)
|
||||||
|
safe_print(f"主机: {host}")
|
||||||
|
safe_print(f"端口: {port}")
|
||||||
|
safe_print()
|
||||||
|
|
||||||
|
# 1. 测试网络连通性
|
||||||
|
safe_print("[1] 测试网络连通性 (Ping)...")
|
||||||
|
try:
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(
|
||||||
|
["ping", "-n", "2", host],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
if "TTL" in result.stdout or "TTL" in result.stderr:
|
||||||
|
safe_print("[OK] 网络连通正常")
|
||||||
|
else:
|
||||||
|
safe_print("[X] 网络不通")
|
||||||
|
except Exception as e:
|
||||||
|
safe_print(f"[!] Ping测试失败: {e}")
|
||||||
|
safe_print()
|
||||||
|
|
||||||
|
# 2. 测试端口是否开放
|
||||||
|
safe_print(f"[2] 测试端口 {port} 是否开放...")
|
||||||
|
if test_port(host, port, timeout=10):
|
||||||
|
safe_print(f"[OK] 端口 {port} 开放")
|
||||||
|
else:
|
||||||
|
safe_print(f"[X] 端口 {port} 无法连接")
|
||||||
|
safe_print()
|
||||||
|
safe_print("可能的原因:")
|
||||||
|
safe_print(" 1. MySQL服务器防火墙未开放3306端口")
|
||||||
|
safe_print(" 2. MySQL配置只允许localhost连接")
|
||||||
|
safe_print(" 3. 云服务商安全组规则阻止了3306端口")
|
||||||
|
safe_print(" 4. MySQL服务未启动")
|
||||||
|
safe_print()
|
||||||
|
safe_print("解决方案:")
|
||||||
|
safe_print(" 1. 检查MySQL服务器防火墙配置:")
|
||||||
|
safe_print(" - Linux: sudo ufw allow 3306/tcp")
|
||||||
|
safe_print(" - Windows: 在防火墙中添加入站规则")
|
||||||
|
safe_print(" 2. 检查MySQL配置文件 (my.cnf 或 my.ini):")
|
||||||
|
safe_print(" - 确保 bind-address = 0.0.0.0 (不是127.0.0.1)")
|
||||||
|
safe_print(" 3. 检查云服务商安全组:")
|
||||||
|
safe_print(" - 添加规则允许3306端口入站")
|
||||||
|
safe_print(" 4. 使用SSH隧道连接:")
|
||||||
|
safe_print(" ssh -L 3306:localhost:3306 user@jeason.online")
|
||||||
|
safe_print()
|
||||||
|
|
||||||
|
# 3. 尝试使用PyMySQL连接
|
||||||
|
safe_print("[3] 尝试使用PyMySQL连接...")
|
||||||
|
try:
|
||||||
|
import pymysql
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
user="tsp_assistant",
|
||||||
|
password="123456",
|
||||||
|
database="tsp_assistant",
|
||||||
|
connect_timeout=10,
|
||||||
|
read_timeout=10,
|
||||||
|
write_timeout=10
|
||||||
|
)
|
||||||
|
safe_print("[OK] MySQL连接成功!")
|
||||||
|
connection.close()
|
||||||
|
except Exception as e:
|
||||||
|
safe_print(f"[X] MySQL连接失败: {e}")
|
||||||
|
safe_print()
|
||||||
|
if "timed out" in str(e).lower() or "can't connect" in str(e).lower():
|
||||||
|
safe_print("这是连接超时错误,说明端口无法访问。")
|
||||||
|
safe_print("请按照上面的解决方案检查服务器配置。")
|
||||||
|
safe_print()
|
||||||
|
|
||||||
|
safe_print("=" * 60)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_mysql_connection()
|
||||||
|
|
||||||
Reference in New Issue
Block a user