java 代码沙箱实现

本文讲述了如何构建一个Java代码沙箱,涉及编译、执行流程,以及确保安全性的措施,如用户代码隔离、编译错误处理和超时控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java 代码沙箱的实现篇

在线判题系统的核心功能模块



前言

代码沙箱其实就是java的编译执行过程,我们只需要完成这些过程即可,需要注意的是,防止写入的代码带病毒,乱写入,死循环之类的问题,我们可以用黑白名单来解决,比如把File加入黑名单

代码沙箱实现逻辑

1、编译前的准备

1.传入的参数

public class ExecuteCodeRequest {
   

    private List<String> inputList;

    private String code;

    private String language;
}
  • 题目需要输入的参数集合
  • 代码内容
  • 使用编译语言

2.传出结果参数类

public class ExecuteCodeResponse {
   

    private List<String> outputList;

    /**
     * 接口信息
     */
    private String message;

    /**
     * 执行状态
     */
    private Integer status;

    /**
     * 判题信息
     */
    private JudgeInfo judgeInfo;
}
  • 我们应该都知道,每一个需要判题程序可以用很多不同的类名,所以我们固定类名,这样我们的java代码在的时候执行的时候就不会那么的麻烦,只需要写好一个字符串为javac (文件路径),就能够生成一个Main的class类,然后执行即可。
  private static final String GLOBAL_JAVA_CLASS_NAME = "Main.java";

2、存放代码及编译代码

将用户代码保存为文件

   /**
     * 1. 把用户的代码保存为文件
     * @param code 用户代码
     * @return
     */
    public File saveCodeToFile(String code) {
   
        String userDir = System.getProperty("user.dir");
        String globalCodePathName = userDir + File.separator + GLOBAL_CODE_DIR_NAME;
        // 判断全局代码目录是否存在,没有则新建
        if (!FileUtil.exist(globalCodePathName)) {
   
            FileUtil.mkdir(globalCodePathName);
        }

        // 把用户的代码隔离存放
        String userCodeParentPath = globalCodePathName + File.separator + UUID.randomUUID();
        String userCodePath = userCodeParentPath + File.separator + GLOBAL_JAVA_CLASS_NAME;
        File userCodeFile = FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8);
        return userCodeFile;
    }

我们固定一个位置,来存放我们的代码,后续我们执行完成后将其删除

Process类

Process 类通常用于表示和管理操作系统中的进程。在多任务操作系统中,进程是执行中的程序实例,它包含程序计数器、寄存器、堆栈和程序执行的内存区域等。不同的编程语言或框架可能有不同的 Process 类实现,但通常它们都提供了一些共同的功能。
- 方法

  • Start()
    描述:启动进程。
    参数:可能包括命令行参数、工作目录等。
    返回值:通常无返回值,但可能抛出异常。

  • Stop() 或 Kill()
    描述:停止或终止进程。
    参数:可能包括终止信号等。
    返回值:通常无返回值,但可能抛出异常。

  • WaitForExit()
    描述:等待进程退出。
    参数:可能包括超时时间。
    返回值:通常返回进程的退出代码。

  • Read() 或 GetOutput()
    描述:读取进程的输出。
    参数:可能包括读取的缓冲区大小等。
    返回值:进程的输出内容。

  • Write() 或 Input()
    描述:向进程发送输入。
    参数:要发送的输入内容。
    返回值:通常无返回值,但可能抛出异常。

编译代码

 /**
     * 2、编译代码
     * @param userCodeFile
     * @return
     */
    public ExecuteMessage compileFile(File userCodeFile) {
   
        String compileCmd = String.format("javac -encoding utf-8 %s", userCodeFile.getAbsolutePath());
        try {
   
            Process compileProcess = Runtime.getRuntime().exec(compileCmd);
            ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(compileProcess, "编译");
            log.info("{},{}",executeMessage.getExitValue(),executeMessage.getErrorMessage());
            if (exec
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值