I am currently using a raspberry pi (RPI) with LAMP to host my webpage on my local network which uses websocket to stream some data representing the state of an LED. My problem is that, upon trying to establish the websocket connection, I get the following error:
WebSocket connection to 'ws://raspberrypi:8080/' failed: Error in
connection establishment: net::ERR_NAME_NOT_RESOLVED
I believe my error is just due to incorrect URL but I did not find another example of how to solve this error in my research.
This error occurs when I try to establish a connection on my laptop over LAN. If I go to my browser on my raspberry pi and try to establish the websocket, this error does not occur. So does this mean that perhaps my server (apache2) is getting in the way?
Here is my Javascript file for the client:
addEventListener('load',init);
function init() {
console.log('page ready');
var ws = new WebSocket('ws://raspberrypi:8080/');
console.log(ws);
}
Here is my python script which outputs the data I want to stream:
from gpiozero import LED
import time
import sys
if __name__ == "__main__":
led = LED(3);
while True:
led.on()
print 1
sys.stdout.flush() #flush: print to screen immediately
time.sleep(1.5)
led.off()
print 0
sys.stdout.flush() #flush: print to screen immediately
time.sleep(1.5)
And here is the terminal feedback from establishing the websocket on the pi:
snapshot
Turns out Apache is a http server, and cannot support websockets (without 3rd party software). I have now successfully set up a websocket using Flask-SocketIO.
This looks like a sheer dns issue.
You might want to edit your hosts file (under linux it's usually /etc/hosts, under windows it should be c:\windows\system32\drivers\etc) to include raspberrypi's ip. Something like:
raspberrypi 192.168.0.20
where the ip address is your raspberry's ip
Related
I have a LM068 BLE serial adapter which I'm trying to communicate with from a web app. I have tested it from the nRF Connect app on Android, where the communication works fine.
The characteristic has the properties "notify" and "writeWithoutResponse".
When calling characteristic.startNotifications() I get an error "GATT Error: invalid attribute length.".
Calling characteristic.writeValue() successfully sends the data, and I can see the incoming data in my serial monitor. When sending data from the serial terminal, the characteristicvaluechanged event never fires. Notifications works from the nRF Connect app.
This is part of my current code:
const characteristic = await service.getCharacteristic(characteristicName)
try {
await characteristic.startNotifications()
} catch (e) {
console.log(e.message)
// GATT Error: invalid attribute length.
}
const encoder = new TextEncoder('utf-8')
characteristic.writeValue(encoder.encode('test')) // Works
characteristic.addEventListener('characteristicvaluechanged', handleValueChanged) // Never gets called
So it turns out that the way I was testing the web app was the issue. I didn't have a BLE dongle for my workstation, so I was using my phone to access my development server. Of course web bluetooth needs to be either run on localhost or from https, so I simply ran the development server on https and accessed it on the network from my phone (like https://192.168.0.x). I proceeded even though chrome deemed it unsafe, but apparently only part of web bluetooth works this way.
Pairing and writeWithoutResponse works with an unsigned certificate. Notifications does not.
I'm leaving this here in case anyone else makes the same mistake.
In Node.js, I have implemented a WebSocket server which is used by a smartphone app. In some cases I got this kind of error (Invalid WebSocket frame: RSV1 must be clear):
This kind of application is running on many different servers across the world, but have the problem only with one instance. The app crashes randomly when using the communication between smartphones (Android or IOS) but it did not crash if I try to send messages over WebSocket using Java.
Looking at the doc of WebSocket specification have found that:
Currently, I can't find what could be wrong. Do you think it could be some "network set-up issue"?
The libraries used for WebSocket in Node.js is ws 6.2.1.
The service is running inside a docker using alpine:8 image. As I told I have a problem only in one environment in all other environments everything works fine. Any idea what else to check?
Well in my case i was sending an object, when i JSON.stringify() it , it started working
For my case I put in return and it solves my issue:
Before:
if (pathname === "/foo/1") {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
}
After:
if (pathname === "/foo/1") {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
return;
}
I think the RSV1 bit can be related to compression setting. There is a similar question to yours ("Invalid WebSocket frame: RSV1 must be clear) here: "Error: Invalid WebSocket frame: RSV1 must be clear" while using Socket.IO
All you need to do is on the server side, pass on an option related to the
"Sec-WebSocket-Extensions: permessage-deflate;"
,
for example,
new Server({
perMessageDeflate {
...
}
});
I am using SignalR in a web application that is hosted on a separate server that has nothing to do with the client.
In the code, I have a function that connects to a SignalR Self-Hosted Service (C#) that is running on the client's computer who is clicking / doing things on the web application (it has been installed by the client). If the client clicks a certain button on my web application, then my service will get data sent to it from the JavaScript code since my server is running on http://*:8080.
Everything appears to be working fine. My question is, how?
My web application is setting the connection in the Server Side JS Code to say this
MyWebApp.cshtml
//Set the hubs URL for the connection
$.connection.hub.url = "http://localhost:8080/signalr";
My C# Service running on the client's computer in the background (that has been installed) is saying this:
MyService.cs
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("Service started");
//string url = "http://localhost:8080";
string url = "http://*:8080";
SignalR = WebApp.Start(url);
eventLog1.WriteEntry("Server running on " + url);
}
How is it possible that they are even communicating when the server side code is saying "Hey look for localhost on 8080!"
And the service says "Hey start on *:8080!" ( I don't even understand what * means)
Last but not least, if I uncomment the line in my service that is currently commented out and use that to start the service it will not work! Why will my service start up on http//*:8080 but not on http://localhost:8080 ?
This code:
WebApp.Start("http://*:8080")
Says "listen for connections on port 8080 on any IP address available". So it will bind to localhost (127.0.0.1) and any other assigned IP addresses the machine has. It is basically a wildcard binding.
This code:
$.connection.hub.url = "http://localhost:8080/signalr";
Says the server is on localhost which resolves to 127.0.0.1.
For your last point as to why it doesn't work if the server started on http://localhost:8080, I assume this is because SignalR is having trouble mapping to the correct IP address. Try using http://127.0.0.1:8080 instead.
I'm just trying to get a very basic websocket connection over internet. The code seems fine - because it works when connecting to localhost - but for some reason fails when I try to use it over the internet. I'm using the websockets library, and my server looks like this:
#!/usr/bin/env python3
import asyncio
import websockets
from logging import getLogger, INFO, StreamHandler
logger = getLogger('websockets')
logger.setLevel(INFO)
logger.addHandler(StreamHandler())
clients = set()
async def handler(websocket, path):
global clients
clients.add(websocket)
try:
await asyncio.wait([ws.send("Hello!") for ws in clients])
await asyncio.sleep(10)
finally:
clients.remove(websocket)
start_server = websockets.serve(handler, host='127.0.0.1', port=6969)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
and the client looks like this:
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>Chat</title>
</head>
<body style="margin:0">
<script type="text/javascript">
var ws = new WebSocket("ws://127.0.0.1:6969/");
var messages = document.getElementById('messages');
ws.onmessage = function (event) {
var messages = document.getElementById('messages');
var message = document.createElement('li');
var content = document.createTextNode(event.data);
message.appendChild(content);
messages.appendChild(message);
};
</script>
Messages:
<ul id="messages"><li>Hello!</li></ul>
</body></html>
So the issue is that the client above works fine, until I run the server on my Ubuntu machine (and I've made sure to forward port 6969 to that machine) and try to connect over the internet. Hostname resolution is working fine, because I can ssh in to start the server, but trying to connect to the websocket always shows me the error message:
Firefox can’t establish a connection to the server at ws://<remote server url>:6969/.
or similiar for other browsers. Also, in case anyone was wondering, the logger isn't outputting anything useful (since the connection is failing the server isn't doing anything).
Your line:
websockets.serve(handler, host='127.0.0.1', port=6969)
provides a specific address on which the websockets server listens. Your server will only listen on that address; any requests to any other address will never be seen.
From https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.create_server :
The host parameter can be a string, in that case the TCP server is bound to host and port. The host parameter can also be a sequence of strings and in that case the TCP server is bound to all hosts of the sequence. If host is an empty string or None, all interfaces are assumed and a list of multiple sockets will be returned (most likely one for IPv4 and another one for IPv6).
You have bound your webserver to 127.0.0.1, which is a special address that only ever refers to the local machine. This address is also known as localhost. No other machine can ever connect to your localhost.
The solution is to provide an empty string or None (the default value). In this case, your web server will listen for requests sent to any address.
websockets.serve(handler, port=6969)
So, I have a Express NodeJS server that is making a connection with another app via an upagraded WebSocket uri for a data feed. If this app goes down, then obviously the WebSocket connection gets closed. I need to reconnect with this uri once the app comes back online.
My first approach was to use a while loop in the socket.onclose function to keep attempting to make the re-connection once the app comes back online, but this didn't seem to work as planned. My code looks like this:
socket.onclose = function(){
while(socket.readyState != 1){
try{
socket = new WebSocket("URI");
console.log("connection status: " + socket.readyState);
}
catch(err) {
//send message to console
}
}
};
This approach keeps giving me a socket.readyState of 0, even after the app the URI is accessing is back online.
Another approach I took was to use the JavaScript setTimout function to attempt to make the connection by using an exponential backoff algorithm. Using this approach, my code in the socket.onclose function looks like this:
socket.onclose = function(){
var time = generateInterval(reconnAttempts); //generateInterval generates the random time based on the exponential backoff algorithm
setTimeout(function(){
reconnAttempts++; //another attempt so increment reconnAttempts
socket = new WebSocket("URI");
}, time);
};
The problem with this attempt is that if the app is still offline when the socket connection is attempted, I get the following error, for obvious reasons, and the node script terminates:
events.js:85
throw er; // Unhandled 'error' event
Error: connect ECONNREFUSED
at exports._errnoException (util.js:746:11)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1010:19)
I also began using the forever node module to ensure that my node script is always running and to make sure it gets restarted after an unexpected exit. Even though I'm using forever, after a few restarts, forever just stops the script anyway.
I am basically just looking for a way to make my NodeJS server more robust and automatically re-connect with another server that may have gone down for some reason, instead of having to manually restart the node script.
Am I completely off base with my attempts? I am a noob when it comes to NodeJS so it may even be something stupid that I'm overlooking, but I have been researching this for a day or so now and all of my attempts don't seem to work as planned.
Any suggestions would be greatly appreciated! Thanks!
Few suggestions
1) Start using domain which prevents your app from an unexpected termination. Ie your app will run under the domain(run method of domain). You can implement some alert mechanism such as email or sms to which will notify when any error occurs.
2) Start using socket.io for websocket communication, it automatically handles the reconnection. Socket.io uses keep-alive heartbeat and continuously polls from the server.
3) Start using pm2 instead of forever. Pm2 allows clustering for your app which improves the performance.
I think this may improve your app's performance, stability and robustness.