Skip to content

Instantly share code, notes, and snippets.

@Xaekai
Created July 11, 2016 18:12
Show Gist options
  • 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);
}
@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.

@dominikj111
Copy link

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