본문 바로가기
컴퓨터/웹 : JS

[Node.js] 노드 서버 파이썬 연동 방법/node.js 파이썬 코드 실행

by 도도새 도 2023. 3. 20.

Node.js 파이썬 연동

 

 프로젝트 진행 중 딥러닝 모델을 Node.js환경에서 실행시켜야 할 필요가 있었다. 이를 위해 tensorflow.js로 시도를 하였으나, 관련 모듈이 설치되지 않는 문제가 있었다. 정확하게는 모듈을 .json형식으로 바꿔주는 부분이 안 되었다.

 

 그렇기에 어쩔 수 없이 파이썬 코드 자체를 실행시키는 방법도 고민하게 되었다. 아래는 그 고민의 결과이다.

 

child process이용

 

 node.js에서 기본적을 제공해주는 child process를 이용하면 생각보다 쉽게 파이썬 파일을 실행할 수 있다.

문서: https://nodejs.org/api/child_process.html

 

Child process | Node.js v19.8.1 Documentation

Child process# Source Code: lib/child_process.js The node:child_process module provides the ability to spawn subprocesses in a manner that is similar, but not identical, to popen(3). This capability is primarily provided by the child_process.spawn() functi

nodejs.org

 

 

 이 부분을 읽으면 spawnSync()를 사용하면 동기적으로 자식 프로세스를 읽어와 사용 가능하다고 한다. 나는 파이썬 코드를 읽어오기 전까지 다른 동작이 수행되는 것을 원치 않으므로 Sync를 사용해보겠다.

 

해당 함수는 아래의 인자들을 가진다.

https://nodejs.org/api/child_process.html#child_processspawnsynccommand-args-options

 

Child process | Node.js v19.8.1 Documentation

Child process# Source Code: lib/child_process.js The node:child_process module provides the ability to spawn subprocesses in a manner that is similar, but not identical, to popen(3). This capability is primarily provided by the child_process.spawn() functi

nodejs.org

spawn: 생성

command : 수행할 커맨드

arg : 문자열로 된 인자들의 리스트

optins : 다양한 옵션 존재한다.

returns : <object>

pid : 자식 프로세스 아이디

output : stdio output의 결과 배열

stdout : output[1]의 내용

stderr : output[2]의 내용

status : 서브프로세스의 exit 코드

...

 

사용되는 예제는 아래와 같다.

spawn 사용 예제

 

그러니까 위는 ls lh /usr라는 명령어를 사용하는 예제이다. -lh옵션은 ls명령어의 옵션으로, 파일 크기, 권한 등을 출력 내용에 포함한다고 한다.

 

여기에 이를 테면 python helloWorld.py나, 인자가 있다면 python helloWorld.py a b 이런 식으로 넣으면 되겠다.

 

위 함수를 사용한다면,

spawn(‘python’, [‘helloWrold.py’, ‘a’, ‘b’])

라는 형식이 되겠다.

 

*주의*

spawn에 cwd옵션을 따로 주지 않으면 실행되는 파이썬의 현재 디렉토리가 부모 디렉토리를 상속받게 된다. 즉, app.js가 WEB이라는 폴더에 들어있고, 파이썬 코드가 WEB/python/helloWorld.py라는 구조를 가지고있다.

 

app.js에서 spawn('python', ['python/helloWorld.py']를 실행게 되면, 이 helloWorld.py는 WEB이라는 폴더에서 실행한 것으로 된다. 즉, 해당 파이썬 파일 내에서 다른 자산(다른 파이썬 파일, 모델 등)을 불러오는 코드가 존재한다면, (cwd옵션을 넣지 않으면) 부모인 app.js를 기준으로 경로를 작성하여야한다.

 

내가 사용하려는 딥러닝 모델 파이썬 코드는 커맨드라인에서 인자를 받는 방법을 argparse모듈을 사용하여 해결하고 있다. 따라서 나도 간단하게 이를 반영한 helloWorld 코드를 짠다.

 

helloWorld 출력

 

우선은 기본적인 파이썬 노드 실행은,  역시 hello world 출력이다.

 

python

def main ():

   print ("Hello, world!")

if __name__ == "__main__":

   main ()

 

app.js

const { spawn } = require ('child_process');

const python = spawn ('python', ['./python/helloWorld.py']);

python .stdout .on ('data', (data )=>{

   console .log (`stdout : ${data }`);

})

 

전체 코드는 아래와 같다.

 

app.js

const express = require ('express');

const bodyParser = require ('body-parser');

const path = require ('path');

const app = express ();

const { spawn } = require ('child_process');

const python = spawn ('python', ['./python/helloWorld.py']);

//템플릿 엔진 설정

app .set ('view engine', 'ejs');

app .set ('views', path .join (__dirname , 'views'));

app .use (bodyParser .urlencoded ({ extended :true }));

app .use (bodyParser .json ());

python .stdout .on ('data', (data )=>{

   console .log (`stdout : ${data }`);

})

 

app .get ('/', (req , res )=>{

  res .render ('home')

})

// 서버 실행

app .listen (8080 , () => {

  console .log ('Server is running on port 8080');

});

 

결과

파이썬 연동 결과

파이썬의 print값이 잘 나오는 것을 알 수 있다.

 

인자 받아 출력

 

이제 파이썬 코드를 수정해보자. 커맨드 라인으로 인자를 받듯이 서버로부터 인자를 받아 print하도록 할 것이다.

python

import argparse

def main ():

   parser = argparse .ArgumentParser (description ='Hello World program with an argument.')

   parser .add_argument ('arg', help ='argument to be added to the Hello, World! message')

   args = parser .parse_args ()

   print ("Hello, world! {}".format (args .arg))

if __name__ == "__main__":

   main ()

 

arg를 인자로 정의하고 파싱하였다. 그리고 값을 받으면 print로 출력하도록 하였다.

 

그리고 app.js 서버측에서 spawn의 두 번째 인자를 정의하였다.

 

app.js

const python = spawn ('python', ['./python/helloWorld.py', 'I am arguement!!']);

 

결과값은 아래와 같다.

인자 포함 출력

댓글