I'm still a bit new to Sockets and NodeJS, I wanted to be able to communicate to a RoboMaster robot over the Plaintext protocol using NodeJS, not Python like what is explained in the documentation. I'm not sure how to do this using NodeJS and am a bit confused if my application socket is a client or server. I would preferably like to convert the example code in the docs to a NodeJS friendly version, but not sure how. I have looked into things like Socket.io, but I'm not sure if that is what I need to be using.
Any help would be appreciated.
Edit: I found this example, it looks quite similar to what I need but I am not sure.
It turns out that I can use the net module to communicate with the RoboMaster robot. Using the code from here this is what it looks like:
var net = require('net');
var HOST = '192.168.2.1';
var PORT = 40923;
var client = new net.Socket();
client.connect(PORT, HOST, function () {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
// Write a message to the socket as soon as the client is connected, the server will receive it as message from the client
client.write('command;');
});
// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function (data) {
console.log('DATA: ' + data);
// Close the client socket completely
client.destroy();
});
// Add a 'close' event handler for the client socket
client.on('close', function () {
console.log('Connection closed');
});
Related
(unnecessary backstory)
I have a nodejs server with expressjs framework that's proxy streaming a webcam feed. The reason I need this is because the mjpg stream must come from this server due to complex CORS issues.
//proxy from webcam server to avoid CORS complaining
app.get('/stream1',function(req,res){
var url="http://camera.nton.lviv.ua/mjpg/video.mjpg"
request(url).pipe(res);
});
question :
The issue is simple. request(url).pipe(res) never closes, because the source is mjpeg which literally never ends. I need to find a way to force close this pipe when the client(browser; the destination) is no longer available - as in, closes the window.
The other answers did not work for me.
This line var pipe=request(url).pipe(res);
returns the pipe instead of the request object. So I needed to break the line up.
The request object is needed to abort. Calling the .end() didn't work either, but the .abort() did the trick. It took me hours to find the answer that worked for me, so I thought I would share.
app.get('/cam/frontdoor',function(req,res){
var request_options = {
auth: {
user: '',
pass: ''},
url: 'http:/xx.xx.xx.xx/mjpg/video.mjpg',
};
var req_pipe = request(request_options);
req_pipe.pipe(res);
req_pipe.on('error', function(e){
console.log(e)
});
//client quit normally
req.on('end', function(){
console.log('end');
req_pipe.abort();
});
//client quit unexpectedly
req.on('close', function(){
console.log('close');
req_pipe.abort()
})
})
Use socket.io to monitor the remote connection
// install it on your project
npm install socket.io
// require it on server side
var socket = require('socket.io');
// listen for sockets from your server
var mysocks = socket.listen(myexpressappvar);
// keep collection of sockets for use if needed
// its good practice
var connectedSockets = [];
// add event handelers on server side
mysocks.sockets.on("connection", function(socket){
// add socket to our collection
connectedSockets.push(socket);
// you will need to bind their stream id here.
exe.....
// listen for disconnected
socket.on("disconnect", function(){
// remove socket from collection
connections.splice(connections.indexOf(socket), 1);
// destory stream here
exe...
});
});
// last thing, is add socket.io to the client side.
<script src="/socket.io/socket.io.js"></script>
// then call connect from client side js file
var socket = io.connect();
I have found out a simpler way. Add a event listener for client connection closing, and force close the pipe when it happens.
app.get('/stream1',function(req,res){
var url="http://camera.nton.lviv.ua/mjpg/video.mjpg"
var pipe=request(url).pipe(res);
pipe.on('error', function(){
console.log('error handling is needed because pipe will break once pipe.end() is called')
}
//client quit normally
req.on('end', function(){
pipe.end();
}
//client quit unexpectedly
req.on('close', function(){
pipe.end();
}
});
I am trying to connect to a socket.io-client using the following code:
Server:
// Load requirements
var http = require('http'),
io = require('socket.io');
// Create server & socket
var server = http.createServer(function(req, res){
// Send HTML headers and message
res.writeHead(404, {'Content-Type': 'text/html'});
res.end('<h1>Aw, snap! 404</h1>');
});
server.listen(8080);
io = io.listen(server);
// Add a connect listener
io.sockets.on('connection', function(socket) {
console.log('Client connected.');
// Disconnect listener
socket.on('disconnect', function() {
console.log('Client disconnected.');
});
});
Client:
console.log('1');
// Connect to server
var io = require('socket.io-client')
var socket = io.connect('localhost:8080', {reconnect: true});
console.log('2');
// Add a connect listener
socket.on('connect', function(socket) {
console.log('Connected!');
});
console.log('3');
I don't get the Connected console log or Client Connected console log and I don't know why! The code sample is taken from another question posted: Link and I don't see any solution to the problem...
Use the same version of socket io client and server. It will work perfectly.
Also you need to add protocol with path.
change
var socket = io.connect('localhost:8080', {reconnect: true});
to
var socket = io.connect('http://localhost:8080', {reconnect: true});
Assuming you are using a socket.io version greater than 1.0, on the server, change this:
// Add a connect listener
io.sockets.on('connection', function(socket) {
console.log('Client connected.');
// Disconnect listener
socket.on('disconnect', function() {
console.log('Client disconnected.');
});
});
to this:
// Add a connect listener
io.on('connection', function(socket) {
console.log('Client connected.');
// Disconnect listener
socket.on('disconnect', function() {
console.log('Client disconnected.');
});
});
See the socket.io documentation reference here.
You don't want to be listening for this event only on already connected sockets. You want to listen for this event on any socket, even a newly created one.
Also, be very careful when reading socket.io code in random places on the internet. Some things changed significantly from v0.9 to v1.0 (I don't know if this was one of those things or not). You should generally always start with the socket.io documentation site first since that will always represent the latest version. Then, if looking at other internet references, make sure you only use articles that are later than mid-2014. If you don't know the vintage of an article, it's best not to rely on it without corroboration from a more recent article.
you can use localhost. It works for me as well. You must use your ip address and port that works for you
When is the connection event of the net.Server fired vs the net.Socket connect event. Are they the same event? I have seen a code example where the handler for the net.createServer function (which handlers the connection event) also has the following code in it
var server = net.createServer(function (client) {
var id = client.remoteAddress + ':' + client.remotePort;
client.on('connect', function() {
channel.emit('join', id, client);
});
client.on('data', function(data) {
data = data.toString();
channel.emit('broadcast', id, data);
});
});
Is this incorrect? Is this listener not needed/never hit..i.e. the emit should be outside the listener.
Based on the code you post here, I'll assume you are reading Node.js in Action and it's the sample code that cause you the problem. If this is the case, you may reference to this similar question: NodeJS events on('connect') error.
Summary
In short, these 2 events are received by 2 different objects.
connect event is received by socket object and is emitted "when a socket connection is successfully established". On ther other hand, connection event is received by server object and is emitted "when a new connection is made".
Notice when a client hit node and create a socket, the callback for net.createServer(callback) is automatically called, thus you don't have to manually register another event handler on this client-server socket, which is client.on('connect', function() { }); in your code.
Concepts
As #3y3 mentioned, there are 2 ways to use net module in node.js, which are createConnection and createServer.
To better understand how it works, you may use this diagram as sample:
net.createServer
When you require net module and createServer, you basically create a server for clients (browser via http, terminal via telnet, etc.) to connect in.
Consider the following codes:
var net = require('net');
var events = require('events');
var channel = new events.EventEmitter();
var server = net.createServer(function (socket) {
var id = socket.remoteAddress + ': ' + client.remotePort;
console.log('Server connected', id);
channel.emit('join', id, socket);
socket.on('data', function(data) {
data = data.toString();
channel.emit('broadcast', id, data);
});
}).listen(8888);
In this case, the parameter in the callback of createServer is the "socket" between server and client. In the sample code, the author of Node.js in Action call it client, which might be a little confusing for you, but that's actually the same concept: it's a client related object which contains methods for your server to do something.
Notice that this callback is registered on the server and called at the same time the connection is built. This is a result of connection event which is emitted to the server when the client hit port 8888 on server in this case. Any functions you put inside this callback will be execute immediately. In our case, there are three things we did:
Console.log the client id on server
Emit a 'join' event to channel object
Register a event listener for 'data' event (i.e. called when there's data sending from client)
There's no need for client.on('connect', function() { // do something }), and since the callback for server connection event is the one we just mentioned. So what's the purpose of clinet.on('connect')?
net.createConnection
By utilizing this function, you create "a connection to the server" rather then create a server itself. In other words, it just like you open a terminal and use telnet to connect to the server, only that this happens in your server code base (i.e. in your node environment, as the diagram Client x shows)
Consider the following code: (based on #3y3's example again):
var Client = net.createConnection;
var client = Client({port: 8888, localAddress: '127.0.0.1', localPort: 51000});
client.on('connect', function() {
var id = this.localAddress + ': ' + this.localPort;
console.log('Client connected', id);
});
Here, we build a client in node and connect to the server through port 8888, which is what we defined previously. localPort and localAddress are defined arbitrary, just a mimic for a terminal connection in local environment.
We then register an event handler on this client, so when this client is connected to the server, it will receive a connect event and execute this event handler. If you run both snippets in the same file with node, you'll see both
Client connected 127.0.0.1: 51000
Server connected ::ffff:127.0.0.1: 51000
in the console.
Conclusion
If you want to do something when remote clients connect to the server, simply put lines you want to execute in the callback function of net.createServer(function(socket) { // your lines here }).
Use client.on('connect', function() {}); for other manually build clients in your node environment.
For further information about socket object and server object, you may refer to the official document here.
You can play with the following revised codes in your case:
var events = require('events');
var net = require('net');
var channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
channel.on('join', function (id, client) {
this.clients[id] = client;
this.subscriptions[id] = function (senderId, message) {
if (senderId !== id) {
this.clients[id].write(message);
}
};
this.on('broadcast', this.subscriptions[id]);
});
var server = net.createServer(function (client) {
var id = client.remoteAddress + ': ' + client.remotePort;
console.log('Server connected', id);
channel.emit('join', id, client);
client.on('data', function(data) {
data = data.toString();
channel.emit('broadcast', id, data);
});
});
server.listen(8888);
var Client = net.createConnection;
var client = Client({port: 8888, localAddress: '127.0.0.1', localPort: 51000});
client.on('connect', function() {
var id = this.localAddress + ': ' + this.localPort;
console.log('Client connected', id);
});
If your code is same as:
var Client = require('net').createConnection,
client = Client({port:4321});
client.on('connect', function(){
//channel.emit('join', id, client);
channel.emit('join', id, this); //avoid bad closure
});
It is valid code and when connect will emited, the server part emits connection, creates socket object and pass it to connection callback
UPDATE:
Your code is incorrect. You pass to createServer the callback for connection event it same as:
var server = net.createServer();
server.on('connection', callback);
In callback you have yet connected socket object. This is correct:
var server = net.createServer(function (client) {
var id = client.remoteAddress + ':' + client.remotePort;
channel.emit('join', id, client);
client.on('data', function(data) {
data = data.toString();
channel.emit('broadcast', id, data);
});
});
Please read the official Nodejs document for module 'net'.
The crux of your matter is, you have a server socket that you have named 'client' (a confusing name) and it is not a client socket. For a client socket you can subscribe to 'connect' event and not for a server socket.
net.createServer(callback) takes a callback which is called back when a new connection from a client occurs and the callback is passed the server socket. What you are referring to in function(client) is essentially a server socket and the term used 'client' is misleading. Please see the Node.js 'net' module example of createServer. For a server socket all the events listed (e.g data, timeout, end, close etc) are valid except the 'connect' event.
On the contrary to a server socket, if you are to create a client program where you called net.createConnection that will return you a client socket. Of that socket you subscribe to the 'connect' event.
I need to synchronize some of data immediately between some servers with main one.
So I think the best and easiest way is using WebSocket in NodeJS.I have some experienced with socket.io module,but it provide client to use in browser.I looked at engine.io ,it looks like socket.io too.
Is there any library to make WebSocket connection as client with out browser?
(or any alternative safe protocol for my situation?)
If you're going to be transferring data across servers, you aren't limited to using the HTTP protocol. Instead, you can use raw TCP sockets. This is how you'd make a listen server:
var net = require('net');
var server = net.createServer(function(socket) {
// do what you need
socket.write();
socket.end();
});
server.listen(8080);
And this is how you'd connect to it from another Node process:
var net = require('net');
var client = net.connect({port: 8080}, function() {
// we can send data back
client.write();
});
client.on('data', function(data) {
// receive data here
});
client.on('end', function() {
// we received a FIN packet
});
I'm trying to create a test using LearnBoost's socket.io and the node-websocket-client. Communication between the client and server work great. After all communication is done, I close both the client and the server. Yet the program hangs, waiting on some unknown callback. Two questions:
What is the following program waiting for?
Is there a tool for diagnosing outstanding callbacks in node programs?
var connect = require('connect'),
io = require('socket.io'),
WebSocket = require('websocket-client').WebSocket;
var port = 7111;
var server = connect.createServer();
var socket = io.listen(server);
socket.on('connection', function(client) {
client.send('Welcome!');
client.on('message', function(message) {
console.log(message);
});
client.on('disconnect', function() {
console.log('closing');
server.close();
});
});
server.listen(port, function() {
var ws = new WebSocket('ws://localhost:' + port + '/socket.io/websocket');
ws.onmessage = function(message) {
console.log(message.data);
};
setTimeout(function() {
ws.send('~m~3~m~Yo!');
ws.close();
}, 10);
});
EDIT: changed the variable name of the WebSocket to ws to avoid confusion
var socket = io.listen(server);
You've created a socket on a port. You've never closed it.
socket.server.close() closes your (socket.io) socket.
When in doubt read the socket.io github examples
socket.server === server It's the server you pass in, in the liste statement so it's closed. I'm not sure what it's waiting for.
Below a way to shutdown all the connections and be able to run multiple expresso tests (using socket.io and socket.io-client).
The solution is tricky and buggy but works on 0.8.5. The main problem is regarding the library to use websockets (node-websocket-client).
Currently, on socket.io, the OS contributors have patched the websocket client. So, we must do the same on our socket.io-client npm package to be able to use finishClose method on the socket client side. Socket.io-client uses the websocket library as npm package, so you must find the file (websocket.js) and substitute it with the same on socket.io.
Afterwards, you could use finishClose method to ensure the connections are closed and with some custom server/client socket settings, the tests will run correctly.
var io = require("socket.io").listen(port);
io.set('close timeout', .2);
io.set('client store expiration', .2);
var client = require("socket.io-client").connect( "http://localhost", { port: port , 'reconnect': false, 'force new connection': true});
client.on('connect', function() {
client.disconnect();
});
client.on('disconnect', function() {
client.socket.transport.websocket.finishClose();
io.server.close();
});
io.server.on('close', function() {
setTimeout( function() {
done();
}, 500);
});
Hope, somebody can help.
The program is waiting because socket.io (server) is still listening for incoming connections. I don't know of any way to stop listening.