Skip to content

Instantly share code, notes, and snippets.

@Xaekai
Created July 11, 2016 18:12
Show Gist options
  • Select an option

  • Save Xaekai/e1f711cb0ad865deafc11185641c632a to your computer and use it in GitHub Desktop.

Select an option

Save Xaekai/e1f711cb0ad865deafc11185641c632a to your computer and use it in GitHub Desktop.
Example of Interprocess communication in Node.js through a UNIX domain socket
/*
**
** Example of Interprocess communication in Node.js through a UNIX domain socket
**
** Usage:
** server> MODE=server node ipc.example.js
** client> MODE=client node ipc.example.js
**
*/
var net = require('net'),
fs = require('fs'),
connections = {},
server, client, mode
;
// prevent duplicate exit messages
var SHUTDOWN = false;
// Our socket
const SOCKETFILE = '/tmp/unix.sock';
// For simplicity of demonstration, both ends in this one file
switch(process.env["MODE"] || process.env["mode"]){
case "server": mode = "server"; break;
case "client": mode = "client"; break;
default: console.error("Mode not set"); process.exit(1);
}
console.info('Loading interprocess communications test');
console.info(' Mode: %s \n Socket: %s \n Process: %s',mode,SOCKETFILE,process.pid);
function createServer(socket){
console.log('Creating server.');
var server = net.createServer(function(stream) {
console.log('Connection acknowledged.');
// Store all connections so we can terminate them if the server closes.
// An object is better than an array for these.
var self = Date.now();
connections[self] = (stream);
stream.on('end', function() {
console.log('Client disconnected.');
delete connections[self];
});
// Messages are buffers. use toString
stream.on('data', function(msg) {
msg = msg.toString();
if(msg === '__snootbooped'){
console.log("Client's snoot confirmed booped.");
return;
}
console.log('Client:', msg);
if(msg === 'foo'){
stream.write('bar');
}
if(msg === 'baz'){
stream.write('qux');
}
if(msg === 'here come dat boi'){
stream.write('Kill yourself.');
}
});
})
.listen(socket)
.on('connection', function(socket){
console.log('Client connected.');
console.log('Sending boop.');
socket.write('__boop');
//console.log(Object.keys(socket));
})
;
return server;
}
if(mode === "server"){
// check for failed cleanup
console.log('Checking for leftover socket.');
fs.stat(SOCKETFILE, function (err, stats) {
if (err) {
// start server
console.log('No leftover socket found.');
server = createServer(SOCKETFILE); return;
}
// remove file then start server
console.log('Removing leftover socket.')
fs.unlink(SOCKETFILE, function(err){
if(err){
// This should never happen.
console.error(err); process.exit(0);
}
server = createServer(SOCKETFILE); return;
});
});
// close all connections when the user does CTRL-C
function cleanup(){
if(!SHUTDOWN){ SHUTDOWN = true;
console.log('\n',"Terminating.",'\n');
if(Object.keys(connections).length){
let clients = Object.keys(connections);
while(clients.length){
let client = clients.pop();
connections[client].write('__disconnect');
connections[client].end();
}
}
server.close();
process.exit(0);
}
}
process.on('SIGINT', cleanup);
}
if(mode === "client"){
// Connect to server.
console.log("Connecting to server.");
client = net.createConnection(SOCKETFILE)
.on('connect', ()=>{
console.log("Connected.");
})
// Messages are buffers. use toString
.on('data', function(data) {
data = data.toString();
if(data === '__boop'){
console.info('Server sent boop. Confirming our snoot is booped.');
client.write('__snootbooped');
return;
}
if(data === '__disconnect'){
console.log('Server disconnected.')
return cleanup();
}
// Generic message handler
console.info('Server:', data)
})
.on('error', function(data) {
console.error('Server not active.'); process.exit(1);
})
;
// Handle input from stdin.
var inputbuffer = "";
process.stdin.on("data", function (data) {
inputbuffer += data;
if (inputbuffer.indexOf("\n") !== -1) {
var line = inputbuffer.substring(0, inputbuffer.indexOf("\n"));
inputbuffer = inputbuffer.substring(inputbuffer.indexOf("\n") + 1);
// Let the client escape
if(line === 'exit'){ return cleanup(); }
if(line === 'quit'){ return cleanup(); }
client.write(line);
}
});
function cleanup(){
if(!SHUTDOWN){ SHUTDOWN = true;
console.log('\n',"Terminating.",'\n');
client.end();
process.exit(0);
}
}
process.on('SIGINT', cleanup);
}
@jschlesser

jschlesser commented Jun 8, 2018

Copy link
Copy Markdown

When you are processing the data events in the client or the server are the events guaranteed to get whole messages and only 1 message? Would you need to keep a buffer around across multiple data calls in case you get '__b' on one event and 'oop' on another and might you get '__boop__disconn' in one data event and 'ect' in another?

@bbartolome

Copy link
Copy Markdown

Thanks for the example @Xaekai

I've used it to explore IPC over socket files between Docker containers: https://github.com/bbartolome/ipc-test

@hinell

hinell commented Aug 3, 2018

Copy link
Copy Markdown

@bbartolome So, what are results?

@jt3k

jt3k commented Sep 2, 2020

Copy link
Copy Markdown

super! Thanx~!

@originbond

Copy link
Copy Markdown

Very useful. Thank you.

ghost commented Jun 7, 2021

Copy link
Copy Markdown

this will only work for one client, if there is more than 1 client, the clients will get mixed up, AFAICT.

old school IPC sucks, use network protocols instead - TCP etc.

Only if you have no idea what you are doing ;)

@zinahe

zinahe commented Mar 14, 2022

Copy link
Copy Markdown

Thanks a lot, your helped as a very good starting point to something I wanted to do.

@evonox

evonox commented Aug 18, 2023

Copy link
Copy Markdown

Thanks a lot. Your sample is a very good starting point for me as well.

@ClosetGeek-Git

Copy link
Copy Markdown

this will only work for one client, if there is more than 1 client, the clients will get mixed up, AFAICT.

old school IPC sucks, use network protocols instead - TCP etc.

unix sockets are not "old school", they're not simply a set of legacy features that has been floating around but are a set of tools that have been constantly updated over the decades. using any form of IP for IPC is lazy and a waist of time and resources within the service your creating.

@JuriPospelow

Copy link
Copy Markdown

Thank you very much! It help me with my project.

@dominikj111

Copy link
Copy Markdown

Thank you for an example, just noticed that the client.write https://gist.github.com/Xaekai/e1f711cb0ad865deafc11185641c632a#file-ipc-example-js-L161 doesn't write until I'll call the client.end. I tried find some solution, but it seams I need to end and re-create the client any time I want to write to socket. Any thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment