I have created a flask website with python. Now, I'm trying to implement some WebRTC/PeerToPeer functionality. I have managed to connect the two peers by manually copy/pasting the SDP back and forth between them using input fields. Everything is working as supposed.
In stead of manually copy/pasting the SDP back and forth, I want to send the SDP through a websocket from the (vanilla) javascript client side to the python backend. However, this is causing me some issues.
I'm not sure I totally understand how the communication between sockets work (I'm fairly new in that field). The code below is my python server.
import socket
import threading
HEADER = 8192
PORT = 3000
SERVER = '{PRIVATE IP ADDRESS}'
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
def handle_client(conn, addr):
print(f'[NEW CONNECTION] {addr} connected.')
connected = True
while connected:
msg = conn.recv(HEADER)
print(f'[{addr}] {msg}')
conn.close()
def start():
server.listen()
while True:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print(f'[ACTIVE CONNECTIONS] {threading.activeCount() - 1}')
if threading.activeCount() - 1 == 0:
break
start()
In the javascript on the client side, all I do is initialize the websocket using the same IP and port as the server is running on. When I refresh the client html page in the browser, the client socket is sending a message to the server. However, I'm not able to decode this message with utf-8 because of a wrong startbyte or something. I have read that sockets might use different protocols. Does that have anything to say in this case? Also, the javascript websocket never changes readystate from 0 to 1, so it never actually connects.
Am I missing something? Is there an easier or better way to connect the javascript client with the python server?
Related
I barely ask any questions on Stack Overflow, but this one is beyond me. I guess I'm missing something basic as I'm pretty new to Node server.
Our application is pretty basic. The server is supposed to receive a handful of text lines (data), merge and parse them, and once the connection is closed (data sending is over) it sends the data to the api.
var net = require('net');
var fs = require('fs');
const axios = require('axios')
const server = new net.Server();
server.listen(PORT, IP);
server.on("connection", client => {
client.write("Hello\n");
console.log('connected');
let received = "";
client.on("data", data => {
received += data
console.log("Partial data is: " + data);
});
client.on("close", () => {
received = received.toString('utf8');
fs.appendFile('log.txt', received, function (err) {});
received = received.replace(/(?:\r\n|\r|\n)/g, "||");
axios.post(APIADDRESS, {data: received});
console.log('Full data is: '+ {data: received});
});
});
To send the data I'm simply running a netcat or nc using the netcat ipaddress port, that's not a problem. It's connecting fine, status message is received.
The thing is - once I open two or more connections from two DIFFERENT SSh servers something weird happens. I can send the line after line just fine. The server reports back "partial data" debug without problem, for both of them.
However, once I close one of the connections (ctrl+c) they BOTH close.
In the end, only the data from the manually closed connection is received. The other one, from a separate nc on a separate ssh server never reaches the client.on("close") part, it seems. It's just terminated for no reason.
Any ideas? I don't even know where to start.
//EDIT
Just tested it from my pc and some ssh mobile app using separated SSH servers. As soon as ctrl+c is sent at any device it closes the connection for all clients.
//Forgot to mention I'm running pm2 to keep the server up. Once I turned on the script by hand, ignoring pm2 - it works fine. Weird. It is happening because of PM2.
I would guess that you have Putty configured to ‘Share SSH connections if possible’. Per some doc, when doing so:
When this mode is in use, the first PuTTY that connected to a given server becomes the ‘upstream’, which means that it is the one managing the real SSH connection. All subsequent PuTTYs which reuse the connection are referred to as ‘downstreams’: they do not connect to the real server at all, but instead connect to the upstream PuTTY via local inter-process communication methods.
So, if you Ctrl+C the PuTTY session that is managing the actual shared connection, they both lose their connection.
You could presumably disable this shared connection feature at either the client or server end of things since both must be enabled for sharing to occur.
To anyone coming here in the future.
If you are using pm2 with --watch enabled and the text log file is in the same folder as your main server script... That's the reason why it drops the connection after a single client disconnects. It just detects that the log has changed.
I'm not facepalming, that's not even funny.
I need to send data out from my google assistance app to a database. In order to do this, I've created a server that takes the data, packages it, and then sends it out. I have the hostname and port and it works in a normal javascript/node.js program but when I use it in my google assistant app nothing happens. I tried figuring out the problem and it looks like the code just isn't connecting. The code I'm using to send data to the server is as follows:
function sendData(app){
var net = require('net');
var message = {"test": 200};
var thisMessage = JSON.stringify(message);
var client = new net.Socket();
client.connect(<port>, '<hostname>', function() {
app.tell(JSON.stringify(client.address()));
console.log('Connected');
client.write(thisMessage);
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
});
return 0;
}
(NOTE: Port and hostname left out for privacy purposes)
This completely skips over the app.tell, leading me to believe the connection is never made. I know it works asynchronously with the server, however, I don't understand why it isn't connecting whatsoever.
I have tried it both in simulation and on my smartphone with sandbox on and off. Is there a better way to connect? Note that the server I'm connecting to is python-based.
The problem is likely that you're running it on Cloud Functions for Firebase which has a limit on outbound connections under their free "Spark" plan. With this plan, you can only connect to other Google services. This is usually a good way to start understanding how to handle Action requests, but has limitations. To access endpoints outside of Google, you need to upgrade to either their "Flame" fixed price plan or "Blaze" pay-as-you-go plan.
You do not, however, need to run on Google's servers or need to use node.js. All you need is a public HTTPS server with a valid SSL cert. If you are familiar with JSON, you can use any programming language to handle the request and response. If you are familiar with node.js, you just need a node.js server that can create Express request and response objects.
I need to delay when the handshake starts when using the WebSocket API on the browser.
The server is a Nucleo board (L476RG) with a wifi shield IDW01M1.
The client is Firefox v50.1
1. Testing the server
I made Python scripts to establish a WebSocket connection. I noticed that I needed to first "Connect" to the server. Then initiate the exchange after a delay of 600ms
I cannot run my server faster than this. Remember this is a hobby level MCU
2. Testing the client
I made a local server using Python. My Javascript client connects to it with no issues.
#!c:/Python27/python.exe -u
import socket
import time
TCP_IP = '172.24.220.1'
TCP_PORT = 3000
BUFFER_SIZE = 1024
#
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect first
connected = False
while not connected:
try:
s.connect((TCP_IP, TCP_PORT))
connected = True
except Exception as e:
pass
#------------------------------------
time.sleep(0.6)
#------------------------------------
# Send first bytes
s.send("Good-hi")
# Ping pong
data = s.recv(BUFFER_SIZE)
Same issue happens with Python also when using the WebSocket library
#!c:/Python27/python.exe -u
import time
import websocket
from websocket import create_connection
remote = "ws://172.24.220.1:3000"
websocket.enableTrace(True)
ws = websocket.WebSocket()
ws.connect(remote) #<------Need to add delay inside this method
print "WebSocket established"
ws.close()
This page explains what happens inside the WebSocket method.
With Python I can open a socket without any handshake (RAW Socket), then start my handshake by sending manually the headers.
However this is impossible to do in a browser because I can't open RAW sockets.
At least, this is my understanding so far.
Summary, is there a way to first establish a connection between client and server, then start the handshake at will ?
If you use the WebSockets api in javascript.
There is a onopen event that gets fired when the connection is ready.
you could put a setTimeout inside this to delay sending first data.
I don't think you can delay the handshake itself.
Maybe try putting new Websocket inside setTimeout to make sure all files have been served before trying to start connection.
more info here:
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
I have a small SignalR project that I've started that right now all it does is receives a string and echo it back to all connected users.
What I'm wondering is, since SignalR open websockets on my server - how can I connect to the service using regular websockets javascript code? (I have a reason for wanting to do it that way without the SignalR library).
I've watched using chrome developer tools and I found that the address the browser is connecting to is:
ws://localhost:53675/signalr/connect?transport=webSockets&clientProtocol=1.4&connectionToken=YKgNxA6dhmtHya1srzPPIv6KFIYEjLTFOogXqcjPErFcKCmRdjvS2X6A2KmraW%2BrLnRUNf68gYPdOkOOgJ8yRcq4iCDm%2BbUyLejsr2NySNZBvLloWuMIAvgI6oC%2Fyt%2Ba&connectionData=%5B%7B%22name%22%3A%22ophirhubtest%22%7D%5D&tid=7
How do I generate the token?
Then, it seems that the messages going between the client and server are just regular json formatted text (which will be easy to mimic):
{"C":"d-9E7D682A-A,1|E,0|F,1|G,0","S":1,"M":[]}
{"H":"ophirhubtest","M":"Echo","A":["test"],"I":0}
{"C":"d-9E7D682A-A,2|E,0|F,1|G,0","M":[{"H":"ophirHubTest","M":"printEcho","A":["You said: test"]}]}
If I just try to connect than it connects but the connection is quickly closed. If I remove the token it closes immediately.
Is it possible to connect to the WS "manually" ?
Before you can connect to the server there is connection negotiation happening. This is when the server sends all the data needed to send and receive messages. Without connection negotiation you won't be able to connect to the server. Once you implement connection negotiation you will be probably half into implementing a SignalR client. I wrote a blog post describing SignalR protocol which should help you understand how things works underneath and why connecting to the server with your own websocket is not straightforward (or simply impossible if you don't follow the SignalR protocol).
EDIT
The ASP.NET Core version of SignalR now allows connecting to the server with bare webSocket.
I just want to add a that it is possible to connect to ASP.NET Core version of SignalR with websocket but you have to add the magic char 30 at the end of every call you make
const endChar = String.fromCharCode(30);
socket.send(`{"arguments":["arg1"],"streamIds":[],"target":"TestMethod","type":1}${endChar}`);
Great answers by Frédéric Thibault but there is one important thing missing. You need to send the protocol and the version directly after connecting. Otherwise you will get the error:
An unexpected error occurred during connection handshake.
Here is a full working example on how to use signalR with plain JavaScript and WebSockets:
let socket = new WebSocket("wss://your-url");
socket.onopen = function(e) {
console.log("[open] Connection established");
const endChar = String.fromCharCode(30);
// send the protocol & version
socket.send(`{"protocol":"json","version":1}${endChar}`);
};
socket.onmessage = function(event) {
console.log(`[message] Data received from server: ${event.data}`);
// parse server data
const serverData = event.data.substring(0, event.data.length - 1);
// after sending the protocol & version subscribe to your method(s)
if (serverData === "{}") {
const endChar = String.fromCharCode(30);
socket.send(`{"arguments":[],"invocationId":"0","target":"Your-Method","type":1}${endChar}`);
return;
}
// handle server messages
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
console.log('[close] Connection died');
}
};
socket.onerror = function(error) {
console.log(`[error] ${error.message}`);
};
I am new to Node.js and also pretty new to server communication.
I have tried to find previous answers, but they are often concerned about communication between server and client.
I have a different case, so need your considerate helps.
Let's assume a scenario that we have three systems, localhost (i.e., laptop) and two cloud servers. I want to code an js app in the localhost that will slice an array of data into two blocks and send them to the cloud servers (block #1 to the server #1 and block #2 to the server #2). Receiving them, two remote servers start to work at the same time. Then, they do the same computation and send their calculation results to each other if they have updated values.
In this scenario, I want to tackle bolded sentences. I believe using the module "socket.io" will be a proper approach to handle this (especially, remote start and communication) but do not have any clear idea in designing codes. In addition, understanding "socket.io" itself is a bit tricky. If you need further specification on the scenario, please comment.
Along with socket.io, check out a module named Faye (http://faye.jcoglan.com/node.html). I have been using it for a couple of years and really like it. Faye is a publish subscribe communication scheme which would allow you to extend your scenario to as many clients as you need. To install faye on your system, run the following command:
npm install -g faye
Now, here is your server code:
var faye = require('faye');
var Server = new faye.NodeAdapter({mount: ('/FayeServer'), timeout: 120});
//now fire the server up on the port 5555
Server.listen(5555);
//subscribe to channel DataChannel
var Subscription = Server.getClient().subscribe("DataChannel",
function(dataObject){ console.log(dataObject) },
function(status) {
console.log('Subscription Status: ' + status);
//send message with two numbers to any client listening to DataChannel
Server.getClient().publish('/DataChannel', {A:5,B:12});
});
Now, here is the client code:
var faye = require('faye');
//open client to server
var Client = new faye.Client('http://127.0.0.1:5555/FayeServer');
//now subscribe to the channel DataChannel
Client.subscribe('/DataChannel', function(dataObject)
{
Client.publish('/DataChannel', {C:(dataObject.A * dataObject.B)};
});
There is a lot more that can be done, but with this basic framework you can stand up server to N client programs that respond to messages from the server.
You will need to replace 127.0.0.1 with your specific URL and use port numbers and channel names more applicable to your specific application.