백준, 프로그래머스와 같은 알고리즘 문제 사이트를 만들 때, c 또는 cpp 등의 코드(text)를 넘겨주면 .c 또는 .cpp 파일로 저장한 뒤 컴파일하고 실행하여 standard I/O 까지 주는 방법이다.
알고리즘에는 테스트케이스가 여러개이기 때문에 input도 여러 개로 한다.
만약 python code라면 compile과정을 생략한다.
파일은 TypeScript로 작성하였다.
1. 코드
import { exec, spawn } from 'child_process';
function commandC( path: string, code: string, inputs: string[], outputs:string[], limit_time: number ): Promise< string > {
return new Promise((resolve, reject) => {
let compileCommand = `gcc ${path}.c -o ${path}`;
let runCommand = `${path}`;
exec(compileCommand, (compileError) => {
if (compileError) {
console.log(compileError.message);
return reject("build error");
}
var complete = 0;
for ( let i = 0; i < inputs.length; i++ ) {
const child = spawn(runCommand, { stdio: ['pipe', 'pipe', 'pipe'] }); // stdin, stdout, stderr 설정
let output: string = "";
child.stdin.write(inputs[i]);
child.stdin.end();
child.stdout.on('data', (data) => { output = data.toString(); });
child.stderr.on('data', (data) => { reject(`Error: ${data.toString()}`); });
child.on('close', (code) => {
clearTimeout(timeoutId);
if (code === 0) {
if ( outputs[i] == output ) { complete++; }
else { reject(`fail`); }
if ( complete === inputs.length ) {
resolve("pass");
}
}
else { reject(`Child process exited with code ${code}`); }
});
const timeoutId = setTimeout(() => {
child.kill();
reject(`Process timed out after ${limit_time}s`);
}, limit_time * 1000);
}
});
});
}
2. 설명
1. 함수 CommandC는 C언어에 대한 코드를 수행한다.
2. 함수 CommandC의 매개변수 path, code, inputs, outputs, limit_time는 각각 코드를 저장할 file path, 사용자가 작성한 code, 테스트 케이스가 여러 개이므로 inputs[], 테스트 케이스에 대한 정답도 여러 개이므로 outputs, 제한시간 limit_time이다.
3. exec(compileCommand)는 사용자가 작성한 코드를 기반으로 컴파일하는 명령어이다.
4. complete 변수는 테스트케이스 inputs에 대한 정답 개수이며, complete와 inputs.length의 값이 같으면 모두 정답이므로 pass.
5.child = spwan(runCommand)로 컴파일이 완료된 프로그램을 실행하는 것이다.
6. child.stdin.write는 c프로그램 기준으로 scanf에 입력될 값을 보내는 것이고, child.stdin.end는 입력이 종료되었다는 문자 \0을 전송한다.
7. child.stdout.on('data')는 c프로그램 기준으로 출력된 값이 있을 때 발생하는 이벤트
8. clearTimeout은 제한시간 이내에 c프로그램이 종료되었을 때, setTimeout event loop를 종료하는 것이다.
9. setTimeout(()=>{}, limit_time*1000) 은 제한시간이 지날 경우 c프로그램을 강제종료하는 것이다. ms단위이다.
3. 실행 결과
아래와 같이 backend에서 소스코드와 프로그램을 저장하고, spwan으로 실행하여 출력값을 얻은 뒤, pass/fail 판단 후 필요없는 파일은 삭제한다.
소스코드는 필요시 DB 또는 file로 저장해도 무관하다.
나의 경우는 DB에 아래와 같이 저장한다.
'프로그래밍 > NodeJS' 카테고리의 다른 글
[NodeJS] Sematic URL여러개를 하나의 변수로 받아오기 (0) | 2023.03.02 |
---|---|
npm nodemodules import하기 (0) | 2023.01.30 |
[JS] webserver 최대 크기 문제 해결(feat. dropzone) (2) | 2022.12.18 |
nodejs&nginx 연동하기 (0) | 2022.12.04 |
[NodeJS] Buffer 함수 사용법 (0) | 2021.01.26 |
댓글