From 91b942f6e998e5bcb9070f93d16592f7c541b558 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 26 Feb 2014 14:04:09 -0800 Subject: [PATCH] added UDP support and examples --- .../basic/hello-client.js | 2 +- .../basic/world-server.js | 2 +- example/UDPSocket/basic/hello-client.js | 48 ++++ example/UDPSocket/basic/world-server.js | 38 +++ .../basic/hello-client.js | 0 .../basic/world-server.js | 0 lib/client.js | 2 + lib/socketServer.js | 228 +++++++++++++----- node-ipc.js | 97 ++++++-- package.json | 12 +- 10 files changed, 332 insertions(+), 97 deletions(-) rename example/{remote => TCPSocket}/basic/hello-client.js (98%) rename example/{remote => TCPSocket}/basic/world-server.js (98%) create mode 100644 example/UDPSocket/basic/hello-client.js create mode 100644 example/UDPSocket/basic/world-server.js rename example/{local => unixSocket}/basic/hello-client.js (100%) rename example/{local => unixSocket}/basic/world-server.js (100%) diff --git a/example/remote/basic/hello-client.js b/example/TCPSocket/basic/hello-client.js similarity index 98% rename from example/remote/basic/hello-client.js rename to example/TCPSocket/basic/hello-client.js index c88592a..88629be 100644 --- a/example/remote/basic/hello-client.js +++ b/example/TCPSocket/basic/hello-client.js @@ -10,7 +10,7 @@ var ipc=require('../../../node-ipc'); ipc.config.id = 'hello'; ipc.config.retry= 1500; -ipc.connectToTCP( +ipc.connectToNet( 'world', function(){ ipc.of.world.on( diff --git a/example/remote/basic/world-server.js b/example/TCPSocket/basic/world-server.js similarity index 98% rename from example/remote/basic/world-server.js rename to example/TCPSocket/basic/world-server.js index 86b3dae..9f7c675 100644 --- a/example/remote/basic/world-server.js +++ b/example/TCPSocket/basic/world-server.js @@ -10,7 +10,7 @@ var ipc=require('../../../node-ipc'); ipc.config.id = 'world'; ipc.config.retry= 1500; -ipc.serveTCP( +ipc.serveNet( function(){ ipc.server.on( 'message', diff --git a/example/UDPSocket/basic/hello-client.js b/example/UDPSocket/basic/hello-client.js new file mode 100644 index 0000000..7e18482 --- /dev/null +++ b/example/UDPSocket/basic/hello-client.js @@ -0,0 +1,48 @@ +var ipc=require('../../../node-ipc'); + +/***************************************\ + * + * UDP Client is really a UDP server + * + * Dedicated UDP sockets on the same + * machine can not be bound to in the + * traditional client/server method + * + * Every UDP socket is it's own UDP server + * And so must have a unique port on its + * machine, unlike TCP or Unix Sockts + * which can share on the same machine. + * + * *************************************/ + +ipc.config.id = 'hello'; +ipc.config.retry= 1500; + +ipc.serveNet( + 8001, //we set the port here because the world server is already using the default of 8000. So we can not bind to 8000 while world is using it. + 'udp4', + function(){ + ipc.server.on( + 'message', + function(data){ + ipc.log('got Data'); + ipc.log('got a message from '.debug, data.from.variable ,' : '.debug, data.message.variable); + } + ); + ipc.server.emit( + { + address : 'localhost', + port : ipc.config.networkPort + }, + 'message', + { + from : ipc.config.id, + message : 'Hello' + } + ); + } +); + +ipc.server.define.listen.message='This event type listens for message strings as value of data key.'; + +ipc.server.start(); \ No newline at end of file diff --git a/example/UDPSocket/basic/world-server.js b/example/UDPSocket/basic/world-server.js new file mode 100644 index 0000000..b5e3f1e --- /dev/null +++ b/example/UDPSocket/basic/world-server.js @@ -0,0 +1,38 @@ +var ipc=require('../../../node-ipc'); + +/***************************************\ + * + * You should start both hello and world + * then you will see them communicating. + * + * *************************************/ + +ipc.config.id = 'world'; +ipc.config.retry= 1500; + +ipc.serveNet( + 'udp4', + function(){ + console.log(123); + ipc.server.on( + 'message', + function(data,socket){ + ipc.log('got a message from '.debug, data.from.variable ,' : '.debug, data.message.variable); + ipc.server.emit( + socket, + 'message', + { + from : ipc.config.id, + message : data.message+' world!' + } + ); + } + ); + + console.log(ipc.server); + } +); + +ipc.server.define.listen.message='This event type listens for message strings as value of data key.'; + +ipc.server.start(); \ No newline at end of file diff --git a/example/local/basic/hello-client.js b/example/unixSocket/basic/hello-client.js similarity index 100% rename from example/local/basic/hello-client.js rename to example/unixSocket/basic/hello-client.js diff --git a/example/local/basic/world-server.js b/example/unixSocket/basic/world-server.js similarity index 100% rename from example/local/basic/world-server.js rename to example/unixSocket/basic/world-server.js diff --git a/lib/client.js b/lib/client.js index 18a0d34..162513a 100644 --- a/lib/client.js +++ b/lib/client.js @@ -40,12 +40,14 @@ function connect(){ } if(!client.port){ + server.log('Connecting client on Unix Socket :'.debug, client.path.variable); client.socket = net.connect( { path:client.path } ); }else{ + server.log('Connecting client via TCP to'.debug, client.path.variable ,client.port); client.socket = net.connect( { port:client.port, diff --git a/lib/socketServer.js b/lib/socketServer.js index 85226f8..12c9f28 100644 --- a/lib/socketServer.js +++ b/lib/socketServer.js @@ -1,26 +1,45 @@ -var net = require('net'), - fs = require('fs'), +var net = require('net'), + fs = require('fs'), + dgram = require('dgram'), eventParser = require('../lib/eventParser.js'), - pubsub = require('event-pubsub'); + pubsub = require('event-pubsub'); function emit(socket, type, data){ if(!data) data=false; - console.log(type,data) this.log('dispatching event to socket'.debug, ' : ', type.data, data); + var event={ + type:type, + data:data + } + + if(this.udp4 || this.udp6){ + + if(!socket.address || !socket.port){ + this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets'); + this.broadcast(type,data); + return; + } + + this.server.write( + eventParser.format( + event + ), + socket + ) + return; + }; + socket.write( eventParser.format( - { - type:type, - data:data - } + event ) ); }; function broadcast(type,data){ - this.log('broadcasting event to '.debug, this.path.variable,' : ', type.data, data); + this.log('broadcasting event to all known sockets listening to '.debug, this.path.variable,' : ', ((this.port)?this.port:''), type.data, data); if(!data) data=false; @@ -31,8 +50,14 @@ function broadcast(type,data){ } ); - for(var i=0, count=this.sockets.length; i0){ - var e=JSON.parse(data.shift()); - server.log('recieved event of : '.debug,e.type.data,e.data); - - server.sockets.push(socket); - + + if(!server.udp4 && !server.udp6){ + server.server=net.createServer( + serverCreated + ); + }else{ + function UDPWrite(message,socket){ + var data=new Buffer(message, server.config.encoding); + server.server.send( + data, + 0, + data.length, + socket.port, + socket.address, + function(err, bytes) { + if(err){ server.trigger( - e.type, - e.data, - socket - ); + 'error', + function(err){ + server.trigger('error',err); + } + ); } } ); - - server.trigger( - 'connect', - socket - ); - - server.trigger( - 'get.events.broadcasting', - socket - ); - - server.trigger( - 'get.events.listening', - socket - ); } - ); + + server.server=dgram.createSocket( + ((server.udp4)? 'udp4':'udp6') + ); + server.server.write=UDPWrite; + server.server.on( + 'listening', + function () { + serverCreated(server.server) + } + ); + } + + function serverCreated(socket) { + + if(socket.setEncoding) + socket.setEncoding(server.config.encoding); + + server.log('## socket connection to server detected ##'.rainbow); + socket.on( + 'close', + function(socket){ + server.trigger( + 'close', + socket + ); + } + ); + + socket.on( + 'error', + function(err){ + server.trigger('error',err); + } + ); + + socket.on( + 'data', + function(data,UDPSocket){ + data=eventParser.parse(data); + var sock=((server.udp4 || server.udp6)? UDPSocket : socket); + + while(data.length>0){ + var e=JSON.parse(data.shift()); + server.log('received event of : '.debug,e.type.data,e.data); + + server.sockets.push(sock); + + server.trigger( + e.type, + e.data, + sock + ); + } + } + ); + + socket.on( + 'message', + function(msg,rinfo) { + server.log('Received UDP message from '.debug, rinfo.address.variable, rinfo.port); + socket.emit('data',msg.toString(),rinfo); + } + ); + + server.trigger( + 'connect', + socket + ); + + server.trigger( + 'get.events.broadcasting', + socket + ); + + server.trigger( + 'get.events.listening', + socket + ); + } function started(socket){ server.onStart(socket) } if(!port){ + server.log('starting server as'.debug, 'Unix Socket'.variable); server.server.listen( server.path, started @@ -146,10 +223,27 @@ function init(path,config,log,port){ return; } - server.server.listen( - server.port, - server.path, - started + if(!server.udp4 && !server.udp4){ + server.log('starting server as'.debug, 'TCP'.variable); + server.server.listen( + server.port, + server.path, + started + ); + return; + } + + server.log('starting server as'.debug,((server.udp4)? 'udp4':'udp6').variable); + server.server.bind( + server.port, + server.path + ); + + started( + { + address : server.path, + port : server.port + } ); } } diff --git a/node-ipc.js b/node-ipc.js index 9e067b7..47081a0 100644 --- a/node-ipc.js +++ b/node-ipc.js @@ -34,9 +34,9 @@ var defaults={ var ipc = { config : defaults, connectTo : connect, - connectToTCP: connectTCP, + connectToNet: connectNet, serve : serve, - serveTCP : serveTCP, + serveNet : serveNet, of : {}, server : false, log : log @@ -80,29 +80,19 @@ function serve(path,callback){ ); } -function serveTCP(host,port,callback){ +function serveNet(host,port,UDPType,callback){ if(typeof host=='number'){ - callback=port; + callback=UDPType; + UDPType=port; port=host; host=false; } if(typeof host=='function'){ callback=host; + UDPType=false; host=false; port=false; } - if(typeof port=='function'){ - callback=port; - port=false; - } - if(!port){ - ipc.log( - 'Server port not specified, so defaulting to'.notice, - 'ipc.config.networkPort'.variable, - ipc.config.networkPort - ); - port=ipc.config.networkPort; - } if(!host){ ipc.log( 'Server host not specified, so defaulting to'.notice, @@ -111,6 +101,37 @@ function serveTCP(host,port,callback){ ); host=ipc.config.networkHost; } + if(host.toLowerCase()=='udp4' || host.toLowerCase()=='udp6'){ + callback=port; + UDPType=host.toLowerCase(); + port=false; + host=ipc.config.networkHost; + } + + if(typeof port=='string'){ + callback=UDPType; + UDPType=port; + port=false; + } + if(typeof port=='function'){ + callback=port; + UDPType=false; + port=false; + } + if(!port){ + ipc.log( + 'Server port not specified, so defaulting to'.notice, + 'ipc.config.networkPort'.variable, + ipc.config.networkPort + ); + port=ipc.config.networkPort; + } + + if(typeof UDPType=='function'){ + callback=UDPType; + UDPType=false; + } + if(!callback) callback=function(){}; @@ -121,6 +142,11 @@ function serveTCP(host,port,callback){ port ); + if(UDPType) + ipc.server[UDPType]=true; + + console.log(callback.toString()) + ipc.server.on( 'start', callback @@ -175,7 +201,7 @@ function connect(id,path,callback){ callback(); } -function connectTCP(id,host,port,callback){ +function connectNet(id,host,port,callback,UDPType){ if(!id){ ipc.log( 'Service id required'.warn, @@ -183,21 +209,43 @@ function connectTCP(id,host,port,callback){ ); return; } - if(typeof host=='number'){ + UDPType=callback; callback=port; port=host; - host=false; + host=false; } if(typeof host=='function'){ + UDPType=port; callback=host; host=false; port=false; } + if(host=='udp4' || host=='udp6'){ + UDPType=host; + host=false; + port=false; + callback=false; + } + if(!host){ + ipc.log( + 'Server host not specified, so defaulting to'.notice, + 'ipc.config.networkHost'.variable, + ipc.config.networkHost.data + ); + host=ipc.config.networkHost; + } + if(typeof port=='function'){ + UDPType=callback; callback=port; port=false; } + if(typeof port == 'string'){ + UDPType=port; + port=false; + callback=false; + } if(!port){ ipc.log( 'Server port not specified, so defaulting to'.notice, @@ -206,13 +254,10 @@ function connectTCP(id,host,port,callback){ ); port=ipc.config.networkPort; } - if(!host){ - ipc.log( - 'Server host not specified, so defaulting to'.notice, - 'ipc.config.networkHost'.variable, - ipc.config.networkHost.data - ); - host=ipc.config.networkHost; + + if(typeof callback == 'string'){ + UDPType=callback; + callback=false; } if(!callback) callback=function(){}; diff --git a/package.json b/package.json index 5868a67..9ec8013 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-ipc", - "version": "0.0.2", + "version": "0.9.0", "description": "A nodejs module for local and remote Inter Process Communication (IPC) uses Unix Sockets for local communication avoiding the network card for lower overhead and latency. ## Solid but, ### Still under development and lacking documentation, but useable.", "main": "node-ipc.js", "directories": { @@ -29,5 +29,13 @@ "memory" ], "author": "Brandon Nozaki Miller", - "license": "Unlicenced" + "license": "Unlicenced", + "repository": { + "type": "git", + "url": "https://github.com/RIAEvangelist/node-ipc.git" + }, + "bugs": { + "url": "https://github.com/RIAEvangelist/node-ipc/issues" + }, + "homepage": "https://github.com/RIAEvangelist/node-ipc" }