dashboard/backend/network_diagnostic.py

304 lines
9.2 KiB
Python
Raw Normal View History

2025-06-09 14:59:40 +08:00
#!/usr/bin/env python3
"""
网络诊断工具
用于诊断服务器部署后访问外部网站时的网络连接问题
"""
import socket
import requests
import time
import urllib.parse
import subprocess
import platform
from typing import Dict, List
def diagnose_network_connectivity(url: str) -> Dict:
"""
综合诊断网络连接问题
"""
print(f"开始诊断网络连接: {url}")
results = {
'url': url,
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
'tests': {}
}
# 解析URL
try:
parsed_url = urllib.parse.urlparse(url)
hostname = parsed_url.hostname
port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)
results['hostname'] = hostname
results['port'] = port
except Exception as e:
results['error'] = f"URL解析失败: {e}"
return results
# 1. DNS解析测试
results['tests']['dns_resolution'] = test_dns_resolution(hostname)
# 2. TCP连接测试
results['tests']['tcp_connection'] = test_tcp_connection(hostname, port)
# 3. HTTP请求测试
results['tests']['http_request'] = test_http_request(url)
# 4. 系统网络配置检查
results['tests']['system_info'] = get_system_network_info()
# 5. 建议解决方案
results['suggestions'] = generate_suggestions(results['tests'])
return results
def test_dns_resolution(hostname: str) -> Dict:
"""测试DNS解析"""
print(f"测试DNS解析: {hostname}")
test_result = {
'status': 'unknown',
'details': {}
}
try:
start_time = time.time()
ip_address = socket.gethostbyname(hostname)
dns_time = time.time() - start_time
test_result['status'] = 'success'
test_result['details'] = {
'ip_address': ip_address,
'resolution_time': f"{dns_time:.3f}"
}
print(f"DNS解析成功: {hostname} -> {ip_address} ({dns_time:.3f}秒)")
except socket.gaierror as e:
test_result['status'] = 'failed'
test_result['details'] = {
'error': str(e),
'error_code': e.errno if hasattr(e, 'errno') else 'unknown'
}
print(f"DNS解析失败: {e}")
return test_result
def test_tcp_connection(hostname: str, port: int) -> Dict:
"""测试TCP连接"""
print(f"测试TCP连接: {hostname}:{port}")
test_result = {
'status': 'unknown',
'details': {}
}
try:
start_time = time.time()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10) # 10秒超时
result = sock.connect_ex((hostname, port))
connect_time = time.time() - start_time
sock.close()
if result == 0:
test_result['status'] = 'success'
test_result['details'] = {
'connection_time': f"{connect_time:.3f}",
'port_open': True
}
print(f"TCP连接成功: {hostname}:{port} ({connect_time:.3f}秒)")
else:
test_result['status'] = 'failed'
test_result['details'] = {
'connection_time': f"{connect_time:.3f}",
'port_open': False,
'error_code': result
}
print(f"TCP连接失败: {hostname}:{port} (错误代码: {result})")
except Exception as e:
test_result['status'] = 'failed'
test_result['details'] = {
'error': str(e)
}
print(f"TCP连接测试异常: {e}")
return test_result
def test_http_request(url: str) -> Dict:
"""测试HTTP请求"""
print(f"测试HTTP请求: {url}")
test_result = {
'status': 'unknown',
'details': {}
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
start_time = time.time()
response = requests.get(
url,
headers=headers,
timeout=(10, 30), # (连接超时, 读取超时)
verify=False,
allow_redirects=True
)
request_time = time.time() - start_time
test_result['status'] = 'success'
test_result['details'] = {
'status_code': response.status_code,
'request_time': f"{request_time:.3f}",
'content_length': len(response.content),
'encoding': response.encoding,
'headers_count': len(response.headers)
}
print(f"HTTP请求成功: {response.status_code} ({request_time:.3f}秒)")
except requests.exceptions.Timeout as e:
test_result['status'] = 'timeout'
test_result['details'] = {
'error': '请求超时',
'timeout_type': str(type(e).__name__)
}
print(f"HTTP请求超时: {e}")
except requests.exceptions.ConnectionError as e:
test_result['status'] = 'connection_error'
test_result['details'] = {
'error': '连接错误',
'error_detail': str(e)
}
print(f"HTTP连接错误: {e}")
except Exception as e:
test_result['status'] = 'failed'
test_result['details'] = {
'error': str(e)
}
print(f"HTTP请求失败: {e}")
return test_result
def get_system_network_info() -> Dict:
"""获取系统网络信息"""
print("收集系统网络信息...")
info = {
'platform': platform.system(),
'platform_version': platform.version(),
'python_version': platform.python_version()
}
try:
# 获取本机IP地址
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
info['hostname'] = hostname
info['local_ip'] = local_ip
except:
info['hostname'] = 'unknown'
info['local_ip'] = 'unknown'
# 检查网络配置仅在Linux/Unix系统上
if platform.system() in ['Linux', 'Darwin']:
try:
# 检查DNS服务器
with open('/etc/resolv.conf', 'r') as f:
dns_servers = []
for line in f:
if line.startswith('nameserver'):
dns_servers.append(line.split()[1])
info['dns_servers'] = dns_servers
except:
info['dns_servers'] = 'unavailable'
try:
# 检查默认网关
result = subprocess.run(['ip', 'route', 'show', 'default'],
capture_output=True, text=True, timeout=5)
if result.returncode == 0:
info['default_gateway'] = result.stdout.strip()
else:
info['default_gateway'] = 'unavailable'
except:
info['default_gateway'] = 'unavailable'
return info
def generate_suggestions(test_results: Dict) -> List[str]:
"""根据测试结果生成建议"""
suggestions = []
# DNS问题
if test_results.get('dns_resolution', {}).get('status') == 'failed':
suggestions.extend([
"DNS解析失败请检查服务器的DNS配置",
"尝试使用公共DNS服务器 (8.8.8.8, 114.114.114.114)",
"检查 /etc/resolv.conf 文件中的DNS服务器配置"
])
# TCP连接问题
if test_results.get('tcp_connection', {}).get('status') == 'failed':
suggestions.extend([
"TCP连接失败可能是防火墙阻止了连接",
"检查服务器的出站规则设置",
"确认目标端口是否开放"
])
# HTTP请求问题
http_status = test_results.get('http_request', {}).get('status')
if http_status == 'timeout':
suggestions.extend([
"HTTP请求超时网络延迟较高",
"增加超时时间设置",
"考虑使用重试机制"
])
elif http_status == 'connection_error':
suggestions.extend([
"HTTP连接错误可能是网络配置问题",
"检查代理设置",
"确认SSL/TLS证书配置"
])
# 通用建议
if not suggestions:
suggestions.append("网络连接测试基本正常,问题可能在应用层面")
suggestions.extend([
"联系系统管理员检查网络配置",
"考虑使用VPN或代理服务器",
"检查服务器所在云平台的安全组设置"
])
return suggestions
def main():
"""主函数,用于命令行测试"""
test_url = "https://ac.bit.edu.cn"
print("=" * 60)
print("网络连接诊断工具")
print("=" * 60)
results = diagnose_network_connectivity(test_url)
print("\n" + "=" * 60)
print("诊断结果")
print("=" * 60)
for test_name, test_result in results['tests'].items():
print(f"\n{test_name}: {test_result['status']}")
if 'details' in test_result:
for key, value in test_result['details'].items():
print(f" {key}: {value}")
print("\n" + "=" * 60)
print("建议解决方案")
print("=" * 60)
for i, suggestion in enumerate(results['suggestions'], 1):
print(f"{i}. {suggestion}")
if __name__ == "__main__":
main()