134 lines
4.2 KiB
Python
134 lines
4.2 KiB
Python
# platform_utils.py
|
||
"""
|
||
跨平台工具模块,处理不同操作系统的兼容性问题
|
||
"""
|
||
import os
|
||
import sys
|
||
import time
|
||
import select
|
||
from log import logger
|
||
|
||
|
||
def is_windows():
|
||
"""检查是否是Windows系统"""
|
||
return os.name == 'nt' or sys.platform.startswith('win')
|
||
|
||
|
||
def is_linux():
|
||
"""检查是否是Linux系统"""
|
||
return os.name == 'posix' and sys.platform.startswith('linux')
|
||
|
||
|
||
def is_macos():
|
||
"""检查是否是macOS系统"""
|
||
return os.name == 'posix' and sys.platform.startswith('darwin')
|
||
|
||
|
||
def set_non_blocking(fd):
|
||
"""设置文件描述符为非阻塞模式(跨平台)"""
|
||
try:
|
||
if is_windows():
|
||
# Windows系统:使用msvcrt或io模块
|
||
import msvcrt
|
||
import io
|
||
if hasattr(fd, 'fileno'):
|
||
# 对于文件对象
|
||
handle = msvcrt.get_osfhandle(fd.fileno())
|
||
# Windows上的非阻塞设置更复杂,这里使用io模块
|
||
# 实际上,对于Windows上的管道,通常使用异步I/O
|
||
# 这里我们采用简化方案:使用超时读取
|
||
pass
|
||
else:
|
||
# Unix系统:使用fcntl
|
||
import fcntl
|
||
import os as unix_os
|
||
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||
fcntl.fcntl(fd, fcntl.F_SETFL, fl | unix_os.O_NONBLOCK)
|
||
return True
|
||
except ImportError:
|
||
logger.warning("fcntl模块在Windows上不可用")
|
||
except Exception as e:
|
||
logger.warning(f"设置非阻塞模式失败: {str(e)}")
|
||
|
||
return False
|
||
|
||
|
||
def read_with_timeout(fd, timeout=0.5):
|
||
"""
|
||
带超时的读取(跨平台)
|
||
返回:(has_data, data) 或 (False, None)
|
||
"""
|
||
if is_windows():
|
||
# Windows: 使用select检查socket,但对于普通文件/管道可能不支持
|
||
# 这里我们使用简单的轮询
|
||
import time
|
||
start_time = time.time()
|
||
while time.time() - start_time < timeout:
|
||
try:
|
||
data = fd.read(1) # 尝试读取1个字节
|
||
if data:
|
||
# 读取剩余部分
|
||
remaining = fd.read()
|
||
if remaining:
|
||
data += remaining
|
||
return True, data
|
||
except (IOError, OSError) as e:
|
||
if "句柄无效" in str(e) or "bad file descriptor" in str(e):
|
||
return False, None
|
||
# 其他错误,继续等待
|
||
pass
|
||
time.sleep(0.01)
|
||
return False, None
|
||
else:
|
||
# Unix: 使用select
|
||
try:
|
||
ready, _, _ = select.select([fd], [], [], timeout)
|
||
if ready:
|
||
data = fd.read()
|
||
return True, data
|
||
except (ValueError, OSError):
|
||
# 可能文件描述符无效
|
||
pass
|
||
return False, None
|
||
|
||
|
||
def safe_readline(fd, timeout=1.0):
|
||
"""安全读取一行(跨平台)"""
|
||
if is_windows():
|
||
# Windows: 使用简单的读取,带超时
|
||
import time
|
||
line = b""
|
||
start_time = time.time()
|
||
|
||
while time.time() - start_time < timeout:
|
||
try:
|
||
# 尝试读取一个字节
|
||
char = fd.read(1)
|
||
if char:
|
||
line += char
|
||
if char == b'\n':
|
||
return line.decode('utf-8', errors='ignore').strip()
|
||
else:
|
||
# 没有数据
|
||
if line:
|
||
# 有部分数据但没换行符
|
||
return line.decode('utf-8', errors='ignore').strip()
|
||
return None
|
||
except (IOError, OSError) as e:
|
||
if "句柄无效" in str(e) or "bad file descriptor" in str(e):
|
||
return None
|
||
time.sleep(0.01)
|
||
|
||
# 超时
|
||
if line:
|
||
return line.decode('utf-8', errors='ignore').strip()
|
||
return None
|
||
else:
|
||
# Unix: 使用普通readline
|
||
try:
|
||
line = fd.readline()
|
||
if line:
|
||
return line.decode('utf-8', errors='ignore').strip()
|
||
except (IOError, OSError):
|
||
pass
|
||
return None |