[Electron] Electron IPC 모듈로 Electron 통신 방법 파헤치기
Electron의 IPC 개념은 Electron에서 자주 사용되는 기술이다.
ipcMain
과 ipcRenderer
를 사용하여 Main 프로세스
와 Renderer 프로세스
간에 통신을 할 수 있기 때문이다.
이런 개념을 빗대어 보자면 웹 기술에서 Back-End와 Front-End 간 통신을 하기 위해서 그에 맞는 특정 모듈과 기술이 필요하다. Electron에서도 이러한 개념을 담당하는 것이 IPC
모듈이다. 다른 예로 Vue를 다뤄본 사람이라면 Event Bus
개념이나 Props
개념을 알고 있을 텐데 이때 @event('eventName')
으로 이벤트를 수신하고 $emit('eventName')
으로 이벤트를 송신하는 것을 볼 수 있는데 이와 비슷한 개념으로 볼 수 있다.
Electron 공식 문서의 용어 정리 부분을 보면 IPC
에 대하여 이렇게 기록하고 있다.
IPC는 프로세스 간 통신을 의미한다.
Electron은 IPC를 사용하여 Main 프로세스와 Renderer 프로세스 간에 직력화 된 JSON 메시지는 동기적 또는 비동기적으로 통신한다.
- - -통신이란 의미는 글로만 봐서는 파악하기 힘들다.
이번 포스트에서는 이 IPC 모듈에 관한 내용을 알아보고 실제로 간단한 앱을 만들면서 파악해보도록 하자.
IPC 모듈
IPC
는 위에서 설명했듯이 프로세스 간 통신을 의미한다. 여기서 프로세스란 Main 프로세스
와 Renderer 프로세스
를 의미한다.
예를 들어 Main 프로세스는 서버로 생각하고 Renderer 프로세스는 브라우저라고 생각한다면 서버와 브라우저 간 통신을 하기 위한 규약이 필요하다. 이를 Electron에서는 IPC
가 처리하고 있다.
IPC는 on
을 통해 메시지 또는 이벤트를 수신하고 send
를 통해 메시지 또는 이벤트를 전달한다. 이 점을 기억하도록 하자.
ipcMain에서 on
을 통한 이벤트 수신
|
ipcRenderer에서 send
을 통한 이벤트 송신
|
여기서 Main 프로세스
와 Renderer 프로세스
의 정의만 잠깐 짚고 넘어가자.
Main Processor
Main 프로세스
는 일반적으로 우리가 Electron으로 개발할 때 생성하는 main.js
로 볼 수 있다.
이는 Electron 앱의 진입점이기도 하며, 앱의 Life Cycle을 관리한다. 뿐만 아니라 애플리케이션에서 사용되는 메뉴, Dock, 트레이와 같은 네이티브 요소를 관리하며 Main 프로세스는 앱에서 각각의 새로운 Renderer 프로세스를 생성한다.
Chromium에서 이러한 개념을 Browser 프로세스라 하며, Electron에서는 Renderer 프로세스와 혼동을 피하고자 Main 프로세스라 명명한다. 즉, Main 프로세스는 Electron 시스템 내 동작하는 애플리케이션을 제어하는 프로세스로 볼 수 있다.
현재 Electron 11.x 버전에서는 아래와 같은 Main 프로세스 모듈이 존재한다.
- app
- autoUpdater
- BrowserView
- contentTracing
- dialog
- globalShortcut
- inAppPurchase
- ipcMain
- Menu
- MenuItem
- net
- netLog
- nativeTheme
- Notification
- powerMonitor
- powerSaveBlocker
- protocol
- screen
- session
- systemPreferences
- TouchBar
- Tray
- webContents
- webFrameMain
Renderer Processor
Renderer 프로세스
는 Electron 앱의 Chromium 기반의 브라우저 창을 관리하는 모듈이다.
Main 프로세스와 달리 Renderer 프로세스는 여러 개가 존재할 수 있으며, Main 프로세스와는 1:N의 관계를 맺는다.
현재 Electron 11.x 버전에서는 아래와 같은 Main 프로세스 모듈이 존재한다.
- desktopCapturer
- ipcRenderer
- remote
- webFrame
이제 다시 돌아와서 IPC
에 대해 알아보자.
위에서 설명했듯이 IPC
는 ipcMain
과 ipcRenderer
모듈 두 가지로 구분된다.
ipcMain
ipcMan
모듈은 Renderer 프로세스(웹 페이지)가 보내는 메시지 또는 이벤트를 동기적 혹은 비동기적으로 처리한다. 즉, 웹 페이지를 처리하는 프로세스인 Renderer 프로세스가 보내는 메시지를 Main 프로세스는 수신하여 처리하게 된다.
아래에서 ipcRenderer
를 보면 알겠지만 보통 ipcMain에서는 IPC 통신을 할 때 수신만 할 수 있다.
위에서 이벤트 수신은 on
이며 송신은 send
라 하였지만, ipcMain에서는 on
으로 송신을 하며 send
가 아닌 reply
로 회신하는 것이다.
아래 예제를 보자.
ipcMain에서 on
을 통한 이벤트 수신
|
위 예제에서 CHANNEL_NAME
은 메시지를 송신할 이름을 말하며 channel
이라고 한다. 어느 ipcRenderer 프로세스에서 CHANNEL_NAME
으로 메시지를 수신하였고 ipMain 프로세스는 ‘CHANNEL_NAME’로 송신하였다. 그리고 다시 reply
를 통하여 송신 후 다시 응답하였다.
이 응답의 channel
이름은 IPC_RENDERER_CHANNEL_NAME
이다. 이렇게 응답을 하였기에 어느 ipcRenderer 프로세서는 on
을 통하여 IPC_RENDERER_CHANNEL_NAME
채널로 수신할 것이다.
기능 측면에서 send
의 개념도 가능하다. 하지만 ipcMain 프로세스는 ipcRenderer와 같은 send
메소드를 가지고 있진 않다. send
를 하기 위해서는 webContents.send를 이용해야 한다.
webContents.send를 이용한 send 방식
|
ipcMain이 될 수 있는 main.js
에서 IPC_RENDERER_CHANNEL_NAME
채널명으로 수신하고 있다. 이는 어느 ipcRenderer에서 IPC_RENDERER_CHANNEL_NAME
채널명으로 송신을 받고 이후의 처리를 할 수 있을 것이다.
이렇게 되면 ipcMain에서도 ipcRenderer와 동일하게 메시지를 송신할 수 있다.
ipcRenderer
ipcRenderer
모듈은 Renderer 프로세스(웹 페이지)에서 Main 프로세스로 동기 또는 비동기 메시지를 보낼 수 있다. Main 프로세스에서 webContents.send 로 메시지를 보냈다면 수신 역시 가능하다.
보통 웹 페이지 딴에서 HTTP 통신을 통해 받아온 데이터를 보내거나 Main 프로세스를 호출할 경우 사용되며, send
를 통해 송신하고 on
을 통해 수신한다.
ipcRenderer에서 send
을 통한 이벤트 송신
|
지금까지 IPC 통신 방법 중 수신이 가능한 on
과 송신이 가능한 send
에 대해서 설명만 했지만, 이외에도 IPC와 관련된 API들은 많다. 이것에 대해서는 Electron API 문서 - ipcMain와 Electron API 문서 - ipcRenderer를 참고하도록 하자.
예제 만들기
이제 실제로 예제를 만들면서 ipcMain
과 ipcRenderer
모듈이 어떻게 동작하는지 알아보도록 하자.
예제의 동작은 최초 Electron이 구동되면 WenContent.send
를 통해서 Renderer 프로세스(웹 페이지)에 정보를 보낼 것이다. 이후 웹 페이지에서는 값을 입력하고 버튼을 클릭하면 입력된 값을 다시 Main 프로세스로 전달할 것이다. 이렇게 전달받은 값은 다시 변형하여 Renderer 프로세스로 전달하는 과정을 만들 것이다.
환경 구축
가장 빠른 방법. electron-quick-start
boilerplate를 통해서 구축하자.
|
코드 수정
먼저 index.html
을 열어 아래와 같이 수정하자.
index.html
|
간단하게 input과 button 그리고 텍스트를 출력할 수 있는 영역을 두었다.
그다음 renderer.js
를 수정하자.
renderer.js
|
최초 페이지가 로드되면 onWebcontentsValue
를 통해서 텍스트를 설정할 것이다. 이후 input에 값을 입력하고 버튼을 클릭하면 해당 값이 onInputValue
를 통해서 Main 프로세스로 송신될 것이다. 이렇게 송신된 이벤트는 Main 프로세스에서 값을 가공하여 replyInputValue
를 통해 응답할 것이고 Renderer 프로세스에서는 이를 받아 텍스트를 출력할 것이다.
이제 Main 프로세스에서 송신과 수신을 지정하자.
main.js
|
위와 같이 수정 후 아래 코드를 보자.
|
이 코드는 Renderer 프로세스에서 웹 페이지가 완료 후에 호출되는 이벤트이다. 이때 Main 프로세스에서는 webcontents.send
를 통해서 최초에 ipc 통신을 하는 것이다.
이와 같이 Main 프로세스에서도 reply
가 아닌 send
를 통해서 ipc 통신 시 송신이 가능하다.
위 코드에서 BrowserWindow
객체를 생성 시 nodeIntegration: true
를 지정한 이유는 renderer.js
에서 require
를 통해 electron 모듈을 호출하기 위해서이다.
실행
main.js
를 수정하였으므로 npm run start
를 통해 다시 구동해보자.
webcontent.send
를 통해서 최초에 값을 전달 했기 때문에 on load
가 출력되는 것을 볼 수 있다.
이제 input 박스에 값을 입력하고 버튼을 클릭해 보자.
예제에서는 test
를 입력하고 버튼을 클릭하니 결과값은 test(computed)
로 출력되었다. 이는 Main 프로세스에서 수신받은 payload를 가공하여 다시 송신하였기 때문이다.
수신받은 payload를 가공하여 응답
|
여기서 console.log를 남겼기 때문에 콘솔을 확인해보자.
콘솔 로그를 보면 입력된 값이 그대로 출력되는 것을 확인할 수 있다.
이렇게 Electron에서 IPC
통신에 대해서 개념과 예제를 통해서 알아보았다.
정리를 하면 IPC
는 Electron에서 프로세스 간의 통신 방법을 말하며, 모듈에는 icpMain
과 Renderer 프로세스가
가 있다. 서로 간의 이벤트 수신은 on
이며, 송신은 send
이다. 이외에 webContents.send
가 있다.
IPC 통신은 프로세스 간 통신 방법이기에 많이 사용된다. 하지만 중요한 건 Electron은 웹 애플리에션에서 하나의 애플리케이션에 REST API가 같이 있는 격이다. 파일별 분리. API의 설계. 등 구조적으로 잘 관리가 되지 않으면 복잡해질 수 있다.
정리가 되지 않고 구조적이지 않으면 이후에 수만은 IPC 모듈에서 수신 및 송신의 코드 추적이 어려워진다.