客户端断开连接后,文件描述符已经被关闭,但仍有事件在处理中:对 app/sockets/terminal_service.py 文件进行了全面修复

This commit is contained in:
CakeCN
2026-01-07 00:57:27 +08:00
parent 761095d61d
commit a3b3018de7

View File

@@ -29,8 +29,12 @@ terminal_bp = Blueprint('terminal', __name__, url_prefix='/vsc-like')
def set_winsize(fd, row, col, xpix=0, ypix=0): def set_winsize(fd, row, col, xpix=0, ypix=0):
try:
winsize = struct.pack("HHHH", row, col, xpix, ypix) winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize) fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
except (OSError, IOError):
# File descriptor closed or invalid, do nothing
pass
def read_and_forward_pty_output(fd=None, pid=None, room_id=None,namespace=None): def read_and_forward_pty_output(fd=None, pid=None, room_id=None,namespace=None):
@@ -172,7 +176,13 @@ class VSCLikeNameSpace(Namespace):
if fd: if fd:
# print("writing to ptd: %s" % data["input"]) # print("writing to ptd: %s" % data["input"])
# os.write(fd, data["input"].encode('ascii')) # os.write(fd, data["input"].encode('ascii'))
try:
os.write(fd, data["input"].encode()) os.write(fd, data["input"].encode())
except (OSError, IOError):
# File descriptor closed or invalid, clean up
disconnect()
session['terminal_config'] = TERM_INIT_CONFIG
return
def on_resize(self, data): def on_resize(self, data):
@@ -188,10 +198,29 @@ class VSCLikeNameSpace(Namespace):
return return
fd = session.get('terminal_config').get('fd') fd = session.get('terminal_config').get('fd')
if fd: if fd:
# 检查文件描述符是否有效
try:
# 尝试一个简单的操作来检查文件描述符是否有效
os.fstat(fd)
set_winsize(fd, data["rows"], data["cols"]) set_winsize(fd, data["rows"], data["cols"])
except (OSError, IOError):
# 文件描述符无效,清理资源
disconnect()
session['terminal_config'] = TERM_INIT_CONFIG
return
def on_disconnect(self): def on_disconnect(self):
child_pid = session.get('terminal_config', {}).get('child_pid') terminal_config = session.get('terminal_config', {})
child_pid = terminal_config.get('child_pid')
fd = terminal_config.get('fd')
# 先关闭文件描述符,避免其他操作尝试使用无效的文件描述符
if fd:
try:
os.close(fd)
except Exception:
pass
if child_pid: if child_pid:
try: try:
child_process = psutil.Process(child_pid) child_process = psutil.Process(child_pid)
@@ -210,21 +239,14 @@ class VSCLikeNameSpace(Namespace):
pass pass
except psutil.TimeoutExpired: except psutil.TimeoutExpired:
# If process didn't terminate in time, kill it forcefully # If process didn't terminate in time, kill it forcefully
child_process.kill()
try: try:
child_process.kill()
child_process.wait(timeout=1) child_process.wait(timeout=1)
except Exception: except Exception:
pass pass
except Exception as err: except Exception as err:
current_app.logger.error(f'Error terminating process: {err}') current_app.logger.error(f'Error terminating process: {err}')
finally:
# Close the file descriptor if it's open
fd = session.get('terminal_config', {}).get('fd')
if fd:
try:
os.close(fd)
except Exception:
pass
# Reset session config # Reset session config
session['terminal_config'] = TERM_INIT_CONFIG session['terminal_config'] = TERM_INIT_CONFIG
current_app.logger.debug('Client disconnected') current_app.logger.debug('Client disconnected')