Electron: IPC vs. WebSocket
For local Node.js applications, which of these two data exchange modes should you choose?
We'll compare their respective features and performance...
Let's clarify that if WebSocket is available for all Node-based systems, then even a simple server script, similar to that described in the JavaScript section of this site, IPC, when it works only with Electron.
On the server side, WebSocket commands are based on the ws module. Other options with different syntaxes are possible. On the interface side, a standard WebSocket object is used.
WebSocket | IRAQI OIL COMPANY | |
---|---|---|
SERVER |
||
Import | const WebSocketServer = require («ws «) .Server; | const {ipcMain} = require ('electron') . ipcMain |
Create a communication object | w = new WebSocketServer (port) | - |
Waiting for link to open | w.on ("compound," (w) => {}) | - |
Data transfer to interface | w.send (data) | event.sender.send ("channel," data) |
Synchronous data transmission | - | event.returnValue = data |
Retrieving data from an interface | w.on ("message," (m) => {}) | ipcMain.on ("channel," (e, o) => {}) |
Closing of communication channel | w.on ("close," () => {}) | - |
INTERFACE SIZE |
||
Import | - | const ipcRenderer = require ('electron') .ipcRenderer |
Creating an object | const w = new WebSocket (port); | - |
Sending data to the server | w.send (data) | ipcRender.send ("channel," data) |
Synchronous data transmission | - | ipcRender.sendSyc ("channel," data) |
Retrieving data from the server | w.onmessage = function (event) {}) | ipcRender.on ("channel," (event) => {}) |
Closing of communication channel | w.close () | - |
You can see the differences between the two protocols:
- For IPC, there is only one ipc object on the server and one for each window in the interface. We interact with the window, indicating the name of the channel .
For WebSocket, it is the port number that distinguishes the communication points. - IPC has synchronous mode rather than WebSocket .
- But the second is bidirectional: the server can start data exchange .
In terms of capabilities, IPC outperforms synchronous communication. By not using system ports, it also avoids the risk of collision when the port is already in use by another application.
IPC Demo
We will build a basic application with a window and a backend that communicates with the interface in synchronous and asynchronous modes.
The interface sends a "hello server" message to the backend, which responds via a "hello interface."
In asynchronous mode, the listener on the interface waits for a message to be received, on the "message" channel.
In synchronous mode, the server response is the return value of the function that sends the message to the server .
Server ID
const path = require("path")
const { app, BrowserWindow, ipcMain } = require('electron')
const print = console.log
let win
function createWindow() {
win = new BrowserWindow({
width: 960, height: 600,
title:"IPC vs. WebSocket",
webPreferences : { nodeIntegration:true }
})
win.setMenu(null)
const fpath = path.join(__dirname, 'ipc.html')
win.loadURL(fpath)
win.on('closed', () => { win = null })
}
// IPC
ipcMain.on('message', (event, data) => {
print("Received: " + data)
event.sender.send('message', 'Hello interface!')
})
ipcMain.on('message-sync', (event, data) => {
print("Received: " + data)
event.returnValue = 'Hello interface (synchronous)!'
})
// App
app.on('ready', createWindow)
app.on('window-all-closed', () => {
app.quit()
process.exit(1)
})
app.on('quit', function () {
print("Done.")
})
In the demo, the event.sender.send command responds on the same "message" channel that is used when receiving, but it is also possible to send data on different multiple channels (as opposed to synchronous mode).
Browser side code
<!DOCTYPE html>
<html>
<body>
<h1>IPC Demo</h1>
<fieldset id="storage"></fieldset>
<fieldset id="storageSync"></fieldset>
<script>
const {ipcRenderer} = require('electron')
ipcRenderer.on('message', (event, data) => {
document.getElementById("storage").innerHTML = data
})
ipcRenderer.send('message', 'Hello server!')
var answer = ipcRenderer.sendSync('message-sync', 'Hello server sync!')
document.getElementById("storageSync").innerHTML = answer
</script>
</body>
</html>
To run the program, enter "electron ipc.js" in the script directory.
WebSocket Demo
As before, the interface sends a "Hello server!" Message to the backend, which instead sends a "Hello interface!" To the browser.
Server ID
The backend imports the ws module that is included in the archive.
const path = require("path")
const { app, BrowserWindow } = require('electron')
const WebSocket = require("ws")
const wss = new WebSocket.Server( { port: 1040 } )
let win
function main() {
win = new BrowserWindow({
width: 960, height: 600,
title:"WebSocket Demo"
})
win.setMenu(null)
const fpath = path.join(__dirname, 'websocket.html')
win.loadURL(fpath)
win.on('closed', () => { win = null })
wss.on('connection', function (w) {
w.on( 'message' , function (data) {
console.log(data)
})
w.on('close', function() {
console.log("Closed")
})
w.send("Hello interface!")
})
}
app.on('ready', main)
app.on('window-all-closed', () => {
app.quit()
process.exit(1)
})
app.on('quit', function () {
console.log("Done.")
})
Browser side code
The interface uses a standard browser WebSocket object.
<!DOCTYPE html>
<html>
<body>
<h1>WebSocket Demo</h1>
<fieldset id="storage"></fieldset>
<script>
const socket = new WebSocket("ws://localhost:1040");
socket.onmessage = function(event) {
var data = event.data
document.getElementById("storage").innerHTML = data
}
socket.onopen = function() {
socket.send('Hello server!')
}
</script>
</body>
</html>
The code is a little simpler, because only the asynchronous mode is tested and this time you do not need to enable the Electron module.
Type "electron websocket.js" to run the script.
Comparative speeds
My original intention was to continue the comparison with new scripts exchanging a series of data to compare the speed of the two protocols. But when you performed the two previous scripts, you can see that it is useless. While data is instantly displayed using IPC, noticeable time is observed using WebSocket.
And this is normal, IPC is internal to Electron, while WebSocket passes through the computer's network system, with all its necessary restrictions and controls.
Thus, since the decision has been made to use Electron, CPI should also become the preferred method of communication unless a two-way system is required, such as server notifications.
Download Scripts