Skip to content

Instantly share code, notes, and snippets.

@Xaekai
Created July 11, 2016 18:12
Show Gist options
  • Star 68 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save Xaekai/e1f711cb0ad865deafc11185641c632a to your computer and use it in GitHub Desktop.
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);
}
@ORESoftware
Copy link

ORESoftware commented May 20, 2018

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.

@jschlesser
Copy link

jschlesser commented Jun 8, 2018

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

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
Copy link

hinell commented Aug 3, 2018

@bbartolome So, what are results?

@jt3k
Copy link

jt3k commented Sep 2, 2020

super! Thanx~!

@originbond
Copy link

Very useful. Thank you.

Copy link

ghost commented Jun 7, 2021

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
Copy link

zinahe commented Mar 14, 2022

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

@evonox
Copy link

evonox commented Aug 18, 2023

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

@ClosetGeek-Git
Copy link

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

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

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