I want to send information from my Node.js code to Python using sockets. How can I achieve that?
In pseudo-code, what I want is this:
js:
sendInformation(information)
python:
recieveInformation()
sendNewInformation()
js:
recievNewInformation()
You should determine which code is the server and which one is the client. I assume your Python code is your server.
You can run a server in python using:
import socket
HOST = '0.0.0.0'
PORT = 9999
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
And then you can connect your Nodejs client code to the server:
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 9999;
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('Message from client');
});
// 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
Here's my setup:
Raspberry Pi 2 (192.168.1.101):
Sensor recording temperature, pressure and humidity.
Python3 script connected to a Raspberry Pi 3, reading sensor data and sending to Pi 3, in JSON format, every 5 seconds.
Raspberry Pi 3 (192.168.1.100):
Node.js server listening for python client on port 8888.
Socket.io listening for web clients on port 3000 (port 3000 and 80 have been opened on my router).
Web server (on port 80) with a website displaying sensor data.
JavaScript connecting to node server, using socket.io, via foobar.ddns.net:3000.
Misc:
I'm using noip.com to have a domain serving my dynamic IP address, my router lets noip know when my public IP changes. I have a URL that looks like foobar.ddns.net.
This setup seems to be working. The Python script is sending data to the node server, which is forwarding it on to any web client connected, which is displayed correctly on the website.
My issue is that the web client disconnects after 1 round of ping/pong between the client and node server.
Here's the chrome console log when connected to the server and receiving data:
The web client connects, receives some data, does a ping/pong with the server, receives some more data, then when it's supposed to ping/pong again it disconnects, then after a while it tries reconnecting and the cycle continues.
And here's the node.js log:
The first New Connection is the Python client (I'm not sure why the IP is the Pi3 address), the rest are the same web client connecting, being disconnected for ping time out, then reconnecting. The client appears to be disconnecting based on on the servers pingInterval + pingTimeout values.
Changing the pingTimeout and pingInterval values just delays the disconnect.
Here's my code:
Python Client:
import json
import socket
import bme280_sensor
import time
import os
class Connection():
def __init__(self, host, port):
self.host = host
self.port = port
def connect(self):
print('Creating socket')
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
print('Failed to create socket: %s' % msg)
raise
print('Socket created')
server_address = (self.host, self.port)
print('Connecting to %s:%s' % server_address)
try:
self.sock.connect(server_address)
except socket.error as msg:
print('Failed to connect: %s' % msg)
raise
print('Connected')
def shutdown(self):
print('Shutting down')
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
def measure_temp():
bme_data = bme280_sensor.read_all()
obj = {}
obj['temp'] = round(bme_data[2], 2)
obj['humidity'] = round(bme_data[0], 2)
obj['pressure'] = round(bme_data[1], 2)
return json.dumps(obj)
def sendData(sock):
print('Sending data')
while True:
try:
data = 'data,' + measure_temp()
sock.sendall(data.encode())
except socket.error as msg:
print("Cannot send to server: %s" % msg)
break
time.sleep(5)
connection = Connection('192.168.1.100', 8888)
while True:
try:
connection.connect()
sendData(connection.sock)
connection.shutdown()
break
except socket.error as msg:
print('Connection failed, retrying in 3 seconds.')
time.sleep(3)
print('Done')
Node.js Server:
var net = require('net');
var port = 8888;
var server = net.createServer();
// socket io listens for clients on port 3000
var io = require('socket.io')(3000,{
pingInterval: 10000,
pingTimeout: 5000,
});
// server listens for python client on port 8888
server.listen(port);
console.log('Server started');
// store the last data recorded, so when a socket.io client connects, they can get the last reading instead of waiting for the next one
global.last;
server.on('connection', function(socket){
console.log('New server connection ' + socket.address().address);
// when the server recieves data, send it to the connected socket clients
socket.on('data', function(data){
// strip the first 5 characters from the input string, parse json from the result
var actual = generateJSON(data.toString().substring(5));
// store the dta
global.last = actual;
//send the data
io.sockets.emit('data', actual);
});
});
io.on('connection', function(socket){
console.log('New io connection ' + socket.id);
// if the server has data previously recorded, send it to the new client
if(global.last){
io.emit('data', global.last);
}
socket.on('disconnect', function(reason){
console.log('io disconnect: ' + reason);
});
});
function generateJSON(data){
var dataJSON = JSON.parse(data);
var obj = new Object();
obj.temperature = dataJSON.temp;
obj.humidity = dataJSON.humidity;
obj.pressure = dataJSON.pressure;
obj.datetime = new Date().toString();
return JSON.stringify(obj);
}
Website Javascript:
var socket;
var connected = false;
function connect(){
console.log('connecting...')
if(socket){
socket.destroy()
delete socket;
socket = null;
}
socket = io.connect("http://foobar.ddns.net:3000", {
forceNew: true,
reconnection: true,
reconnectionDelay: 3000,
reconnectionDelayMax: 5000,
reconnectionAttempts: Infinity
});
console.log(socket);
socket.on("data", function(data){
var obj = JSON.parse(data);
console.log(data);
$('#temperature-value').text(obj.temperature);
$('#humidity-value').text(obj.humidity);
$('#pressure-value').text(obj.pressure);
lastUpdate = new Date();
});
socket.on('connect_error', function(error){
console.log('connection error: ' + error);
});
socket.on('connect_timeout', function(){
console.log('connection timeout');
});
socket.on('reconnect', function(){
console.log('reconnect');
});
socket.on('reconnect_attempt', function(){
console.log('reconnect attempt');
});
socket.on('reconnect_failed', function(){
console.log('reconnect_failed');
});
socket.on('reconnect_error', function(){
console.log('reconnect_error');
});
socket.on('reconnecting', function(){
console.log('reconnecting');
});
socket.on('ping', function(){
console.log('ping');
});
socket.on('pong', function(ms){
console.log('pong ' + ms + "ms");
});
socket.on('connect', function(){
console.log('connected to server');
connected = true;
});
socket.on('disconnect', function(reason){
console.log('disconnected from server: ' + reason);
connected = false;
});
}
$(document).ready(function(){
connect();
});
I'm accessing the socket.io.js script with this in my index.html:
<script src="http://foobar.ddns.net:3000/socket.io/socket.io.js"></script>
This is functional but the disconnects are rather annoying, I'd rather the client stays connected. I have a feeling that my node.js server is not setup correctly, but I can't figure out what the issue is. If there's a better way to feed data from the python script > node.js server > web clients then please let me know.
Thanks
I've solved the issue! It had nothing to do with node.js or socket.io.
The issue was on the web page I have displaying the data, I had this method to update a span showing the seconds since the last update:
function updateLastUpdateTimer(){
var seconds = (new Date() - lastUpdate) / 1000;
$('#time-since-last-update').text(formatTime(seconds) + " ago");
$('#last-updated-time').text(lastUpdate);
setInterval(updateLastUpdateTimer, 1000);
}
The issue was setInterval when it should have been setTimeout. I realised that my web page was eating up RAM, which was causing the client socket to hang and not send any data to the server, which was causing the time out!
The setInterval method runs a function every x milliseconds. DO NOT put it in the method you want to call! Call it once instead.
To anyone reading this who has the same issue with ping timeout and transport closed disconnects, check your client!
i tumbled across websocket and http.
I have written below example:
var fs = require('fs');
var server = http.createServer(function(request, response) {
console.log ("HTTP Request created...");
// I am responding something here..
});
server.listen(1234, function() {
console.log((new Date()) + ' Server is listening on port 1234');
});
var WebSocketServer = require('websocket').server;
wsServer = new WebSocketServer({
httpServer: server
});
wsServer.on('request', function(re){
var conn = re.accept(null, re.origin);
console.log ("Accepted New Connection..");
conn.on('message', function(message) {
console.log ('message received' + message.utf8Data);
});
});
I tried in two ways connecting to this server.
1) Through Browser.
2) through node.js application
When I tried reaching this server through browser ex: http:IP:1234,
I get "HTTP Request received.." gets printed, where as when I try with
below code in Node.js, I do not see this message getting printed.
var WebSocket = require('ws')
ws = new WebSocket('ws://IP:1234');
ws.on('open', function() {
console.log ("WebSocket opened..");
ws.send('something');
});
ws.on('message', function(message) {
console.log('received: %s', message.data);
});
When I tried to connect to webserver through
ws = new WebSocket('ws://IP:1234');
why is It not getting through HTTP?. My basic understanding is Websocket is just an upgrade on top of HTTP, in that case, I would assume WebSocket(), in turn connectes through HTTP to the server right?. Or Am i confused?.
Websocket requests don't trigger a request event on the HTTP server instance (for which the function you pass to createServer is a listener).
If you want to watch websocket requests on the HTTP server, listen to upgrade events:
server.on('upgrade', function (req, socket, head) { ... });
I assume it's because http will handle the handshake/upgrade itself that this is done through a different event.
On server the disconnect event is triggered after connect when the network had
dropped and the client reconnects.
Client code:
var url ='192.168.1.101', port = '80',
socket = io.connect('http://' + url + ':' + port, {
'reconnect': true,
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 1000
});
//reconnect event
socket.on('reconnect', function (nr) {
console.log('reconnected, nr: ', nr);
});
//connect event
socket.on('connect', function () {
console.log('connected');
});
//disconnect event
socket.on('disconnect', function () {
console.log('disconnected');
});
Server code:
'use strict';
var fs = require('fs'),
express = require('express'),
app = express(),
io = require('socket.io'),
server = require('http').createServer(app),
compress = require('compression'),
socket;
app.use(compress({level: 9}));
server.listen(port, url);
socket = io.listen(server, {'pingTimeout': 1000, 'pingInterval': 3000});
socket.on('connection', function (client) {
console.log('client connected');
client.on('disconnect', function () {
console.log('client disconnected');
});
});
- Result on server if client reconnects:
> client connected
> client disconnected
Can someone explain to me why this is happening?
The client and server exchange heart beat messages while the connection is active. When the server stops receiving these messages it will declare the client disconnected. The client can also disconnect explicitly.
What you are experiencing though is probably the first case. The client has a retry logic so whenever the connection is dropped it'll try to reconnect. I'm not sure why this is happen, you may want to look at the network tab in your browser's console to see what's happening at the request/response level.
REF:
https://github.com/socketio/socket.io/issues/1910
https://github.com/miguelgrinberg/Flask-SocketIO/issues/116
Are you sure that the client disconnected and client connected texts are from the same socket/connection? Maybe first one is from previous connection and it is just delivered to you a bit later than info about new connection?
Try to generate and add some ID numbers to connections/sockets and output them to console along with info messages.
I am trying to connect to an UDP socket on another computer using the UDP socket of node.js and I am getting the following error:
bind EADDRNOTAVAIL192.168.1.50;12345
I am using the following code:
var port = 12345;
var host = "192.168.1.50";
var sock = dgram.createSocket("udp4");
sock.on("listening", function () {
console.log("server listening ");
});
sock.on("error", function (err) {
console.log("server error:\n" + err.stack);
sock.close();
});
//start the UDP server with the radar port 12345
sock.bind(port, host);
any help?
thanks
You can't bind to the remote server address! It doesn't matter what your server ip is, you should bind to one of your local interfaces. If you want to bind on all local interfaces, just bind like following:
sock.bind(port);
You can send UDP datagrams in the following way (Sample code)
var dgram = require('dgram');
var PORT = 12345;
var HOST = '192.168.1.50';
var message = new Buffer('Pinging');
var client = dgram.createSocket('udp4');
client.send(message, 0, message.length, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT);
client.close();
});
Reference: http://www.hacksparrow.com/node-js-udp-server-and-client-example.html
I am writing a simple client server NodeJS application using UDP protocol. The main point of this application is that it requires the use of a broker, whose function, in the given case, is to link the sender with the receiver. The requirements tell me that the sender doesn't need to be aware of the receiver's IP address and port number - it only needs to know the broker's corresponding IP and PORT. Afterwards, the broker will send the client's message to the server, based on the server's IP and PORT.
To clarify the previous(?confusing) paragraph, below you will find a illustration of what I've done so far:
sender.js
var PORT1 = XXXXX;
var HOST = '127.0.0.1';
var fs = require('fs');
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
fs.readFile('Path/to/the/file','utf8', function (err, data) {
if (err) throw err;
var message = new Buffer(data);
client.send(data, 0, message.length, PORT1, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT1);
client.close();
});
});
The code above reads from a file, stores its contents in a buffer and sends it to the broker's port(the broker listens to the same port) and host(which, in my case is the localhost).
broker.js
var PORT1 = XXXXX;
var PORT2 = YYYYY;
var HOST = '127.0.0.1';
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
var client = dgram.createSocket('udp4');
server.on('listening', function () {
var address = server.address();
console.log('UDP broker listening on ' + address.address + ":" + address.port);
});
server.on('message', function (message, remote) {
client.send(message, 0, message.length, PORT2, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT2);
client.close();
});
console.log(remote.address + ':' + remote.port +' - ' + message);
});
server.bind(PORT1, HOST);
Here, PORT1 is the port that the broker listens to(waiting for incoming messages from sender) and PORT2 is the port which transmits the message to the receiver(and correspondingly, the receiver listens to this port).
receiver.js
var PORT2 = YYYYY;
var HOST = '127.0.0.1';
var fs = require('fs');
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
var parser = require('xml2json');
server.on('listening', function () {
var address = server.address();
console.log('UDP receiver listening on ' + address.address + ":" + address.port);
});
server.on('message', function (message, remote) {
console.log(remote.address + ':' + remote.port +' - ' + message);
var contents = fs.writeFile("/Path/To/Written/File", parser.toJson(message),
function(error){
if (error) {
console.log("error writing");
}
console.log("File was saved");
});
});
server.bind(PORT2, HOST);
The receiver gets the message from the broker and writes it to a file in the JSON format.
Here are the results:
Sender
UserName's-MacBook-Pro:UDP server UserName$ node sender.js
UDP message sent to 127.0.0.1:XXXXX
Broker
UserName's-MacBook-Pro:UDP server UserName$ node broker.js
UDP broker listening on 127.0.0.1:XXXXX
127.0.0.1:60009 - <?xml version="1.0"?>
<Some XML content here>
</XML content ends here>
UDP message sent to 127.0.0.1:YYYYY
Receiver
UserName's-MacBook-Pro:UDP server UserName$ node receiver.js
UDP receiver listening on 127.0.0.1:YYYYY
127.0.0.1:63407 - <?xml version="1.0"?>
<XML contents here>
</XML content ends here>
File was saved
I am sorry for the long post, but I want to specify all the details to eliminate(hopefully) any ambiguities. Now, to the matter,
HERE is my question
What changes should I make for the broker in order to solve the following problem:
In case of multiple senders and receivers, the broker should manage the ports to link the sender to the receiver(with any specified criteria).
Thank you in advance!
Take a look in this book "Node.js Design Patterns,Publisher:Packt Publishing By: Mario Casciaro ISBN: 978-1-78328-731-4 Year: 2014" at page 361. There is the exact thing you want to do with very good explanation.
Hope it will help!