I'm trying to connect to a WAMP websocket server using Python and subscribe to receive messages, but I'm not able to achieve it. I have managed to connect using Autobahn on JS with this code:
< script src = "autobahn.js" > < /script> <script >
var conn = new ab.Session('ws://examplehost.com:8443/ws',
function() {
conn.subscribe('channel', function(topic, data) {
console.log(data);
alert('New data arrived: "' + topic + '" : ' + data.title);});},
function() {
console.warn('WebSocket connection closed');
}, {'skipSubprotocolCheck': true});
</script>
But using the same library on Python with below code results on 404 error:
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
class Component(ApplicationSession):
async def onJoin(self, details):
def on_event(i):
print("New data arrived: {}".format(i))
await self.subscribe(on_event, 'channel')
if __name__ == '__main__':
url = "ws://examplehost.com:8443/ws"
runner = ApplicationRunner(url)
runner.run(Component)
And this is the error I get:
failing WebSocket opening handshake ('WebSocket connection upgrade failed (404 - NotFound)')
dropping connection to peer tcp4:123.123.123.123:8443 with abort=True: WebSocket connection upgrade failed (404 - NotFound)
Any idea on how to solve this? After searching a lot maybe using the path /ws on the server is causing some issues, but I'm not sure. I have also tried with many other Python modules, but not luck.
This looks like a webserver issue. My understanding is websockets are created by upgrading reglar HTTP connections.
You need to configure the web server, and any proxy in the middle, to upgrade the configuration.
I've mostly encountered this with nginx. This looks like a good example.
Related
I am developing an app and using the websockets for the server-client communication. The concept is to have the client requesting from the server for messages and a few times the server needs to push some messages to the client (without the latter has requested for them). (I'll use front-end and back-end to describe my app)
The app works when the front-end requests from the back-end but it doesn't for the case where the back-end needs to be the originator of the message (i.e. emit data without the front-end has requested for that). In that case the websocket seems to stall and blocked for a few seconds, until the client disconnects (reason timeout) and connects again. Of course, the topic sent by the back-end/server is never received by the client, i.e. the /non_requested_topic as seen below.
For the BACK-END I am using flask-socketio in PY2.7 and
events_handling.py
#!/usr/bin/env python
from flask import request
from emit_topics import emit_topic
def on_connect():
print("Client {} connected".format(request.sid))
# set the client ID to unrequested.py blah blah
def on_disconnect():
print("Client {} disconnected".format(request.sid))
def on_topic_request(data):
data_rx = "blah blah"
to = request.sid # client
namespace = "my_namespace"
emit_topic(topic_name="/topic_name", data_rx, to, namespace)
emit_topics.py
def emit_topic(topic_name, data, to, namespace):
socket_io.emit(topic_name, data=data, to=to, namespace=namespace)
And then there is a function that calls emit_topic and pushes some data to the client (without the client has requested for them):
unrequested.py
#!/usr/bin/env python
from emit_topics import emit_topic
def function_a(self):
to = self.client_id # client id that is set every time the client connects
namespace = "my_namespace"
data_rx="Msg from the server"
print("Check the client id {}".format(to)) # this matches with the one observed for the ws
emit_topic (topic_name="/non_requested_topic", data_rx, to, namespace)
For the FRONT-END:
There is an HTML file where:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.min.js"></script>
var socket = io("my_namespace", {'forceNew': true});
var interval_timer;
socket.on('connect', function() {
console.log('Connected to the server');
interval_timer = setInterval(topics_request, 5000);
});
socket.on('disconnect', function() {
console.log('Disconnected from the server');
clearInterval(interval_timer);
});
socket.on("/topic_name", (msg) => {
console.log("/topic_name rx ", msg);
});
socket.on("/non_requested_topic", (msg) => {
console.log("Non requested topic rx ", msg);
});
function topics_request(){
socket.emit("topic_request", {"topic": "/topic_name"}) // some topic name
}
Is a request from the client required first to trigger the /non_requested_topic or is there a way for the client to keep listening to that?
You have several issues with your code.
First of all, Python 2.7 has not been a supported version of Python for Flask-SocketIO for a while. I strong advise you to start using Python 3.
Your use of namespaces in the server is very inconsistent. Your connect and disconnect handlers do not use a namespace. Your on_topic_request function doesn't either. But then the emit_topic function accepts a namespace as an argument, which you set to my_namespace. Why do you use a namespace only when emitting but not when receiving events? Also, namespaces are supposed to start with a slash.
I'm very new to Socket protocol and I'm sure the problem comes from me knowing almost nothing about this. But basically I have a socket on port 5000 on my server and I need to have an angularjs code to listen to this socket. The socket on the server can read whatever I send from another computer (client). But for some reason the angular code can't listen/connect to the socket. Here's what I have right now:
index.html
<html ng-app="MyAwesomeApp">
<head>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/ng-websocket/ng-websocket.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="cnt">
</body>
</html>
and here's the angularjs code:
app.js
var app = angular.module('MyAwesomeApp', ['ngWebsocket']);
app.controller('cnt', function ($websocket) {
var ws = $websocket.$new('ws://localhost:5000');
ws.$on('$open', function () {
ws.$emit('hello', 'world'); // it sends the event 'hello' with data 'world'
})
.$on('test', function (message) { // it listents for 'incoming event'
console.log('something incoming from the server: ' + message);
});
});
and here's the python code that I have for server socket:
#server example
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('localhost', 5000))
serversocket.listen(1) # become a server socket, maximum 5 connections
# print "hello"
while True:
connection, address = serversocket.accept()
print address
while True:
buf = connection.recv(16)
if len(buf) > 0:
connection.sendall(buf)
print buf
# break
Most of the angularjs code comes from https://coderwall.com/p/uhqeqg/html5-websocket-with-angularjs
These are the errors that I get in Chrome
ng-websocket.js:122 WebSocket connection to 'ws://localhost:5000/'
failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
and in Firefox:
Firefox can’t establish a connection to the server at
ws://localhost:5000/.
What you are trying to do is not possible. At least not in a way you want to do it.
WebSockets is an application layer protocol, much like HTTP protocol is. Pay attention at ws part of ws://localhost:5000.
On the other side you are using plain BSD sockets. This is just a raw socket for communication between two parties. It needs an to 'have an idea' about what the other side (AngularJS) is 'speaking', i.e. needs to communicate using same protocol. In BSD sockets case it inherently doesn't.
That is why you get:
ng-websocket.js:122 WebSocket connection to 'ws://localhost:5000/'
failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
To be able to do this, you will need some asynchronous programming framework with WebSockets protocol built on top of it. One suggestion is Autobahn.
How can a Node script send a notification via XMPP to a Jabber user (e.g. via Google Hangouts)? I've looked at libraries like xmpp/client but they seem overkill. Is there a simpler solution?
Simplest way to send a message via XMPP in Node
There is probably no other simpler XMPP client library for Node than node-simple-xmpp.
In this case the minimal Node.js script to send a message to another Jabber user is:
var xmpp = require('simple-xmpp');
var jid = 'testjs#xmpp.jp';
var pwd = 'xyz';
var server = 'xmpp.jp';
var port = 5222;
xmpp.on('online', function(data) {
console.log('Connected with JID: ' + data.jid.user);
xmpp.send('testjs#007jabber.com', 'hello! time is '+new Date(), false);
});
xmpp.on('error', function(err) {
console.error("error:", JSON.stringify(err));
});
xmpp.connect({
jid: jid,
password: pwd,
host: server,
port: port
});
If the two account have never spoken together, a preliminary 'subscribe' is also required:
xmpp.subscribe('testjs#007jabber.com');
As you can see in package.json node-simple-xmpp lib has a dependency on [node-xmpp-client] (https://github.com/xmppjs/xmpp.js/tree/node-xmpp/packages/node-xmpp-client).
Usage with Google Talk/Hangouts
The script above is working (tested) also with Google Talk/Hangouts, you just have to replace xmpp.jpserver with talk.google.com and use a Google account. Turn on https://myaccount.google.com/lesssecureapps to enable Node.js script to sign in with Google account.
Other XMPP libraries
As of https://npms.io/search?q=node-xmpp there are a few other XMPP Client libraries for Node, however almost all of them are dependent on node-xmpp-client or limited to BOSH connection (polling over HTTP).
One interesting lib for those used to Strophe.js on client side seems node-strophe. It is based on Strophe.js release 1.0.2 which is a library for applications that run in any browser. Unfortunately that version didn't support other than BOSH (see Strophe.js changelog), websocket is available only since release 1.1.0.
Exploring alternatives without specific XMPP libraries
An alternative solution without specific XMPP libraries could be using Net module, but in this case you need to manage all XMPP interactions to establish the connection to the server, see https://wiki.xmpp.org/web/Programming_XMPP_Clients .
Below is a very raw example of script trying to initiate the connection with a Jabber server using Net module:
var net = require('net');
var jid = 'testjs#xmpp.jp';
var pwd = 'xyz';
var server = 'xmpp.jp';
var port = 5222;
var msg = '<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0" to="'+server+'">';
var client = new net.Socket();
client.connect(port, server, function() {
console.log('Connected');
client.write(msg);
});
client.on('data', function(data) {
console.log('Received: ' + data);
});
You can see in the console log the correct answer of Jabber server, however from then on it's a mess: you should begin exchanging TLS messages (see https://xmpp.org/rfcs/rfc3920.html#tls)
Conclusions
I think the only feasible alternative is the first one using node-simple-xmpp library.
I'm trying to connect with signalr hub, but I'm getting the following error in javascript:
WebSocket connection to 'ws://dev:777/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=%2BRUC9XodaU4R3Wn3BSLfhZXxLqeLj9fp4XlLJSsxrc36dFuEo6O9GOIGYMdsgSeswY2DTzzJe9qCe9JnqgjwusbYROxjkY%2B6d9FD4MVpox4FLEqNzCF5Y%2BOqrY5ndNs%2FRl7aOoKIYelpGmerXj4mdw%3D%3D&connectionData=%5B%7B%22name%22%3A%22machinehub%22%7D%5D&tid=5' failed: Error during WebSocket handshake: Unexpected response code: 504
and then in console
Could not connect. Invocation of StartMachine failed. Error: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.
I'm using such code to invoke my method from hub which:
self.Run = function (action, parameters, callbacks) {
try {
var connection = $.hubConnection();
connection.logging = self.Debug;
var hub = connection.createHubProxy(self.Name);
registerConnectionEvents(connection);
registerEvents(hub, callbacks);
connection.start({ transport: ['webSockets'] })
.done(function () {
self.debug("Now connected!");
hub.invoke.apply(hub, $.merge([action], parameters)).fail(function (error) {
var msg = 'Invocation of ' + action + ' failed. ' + error;
self.debug(msg);
});
})
.fail(function (error) {
var msg = 'Could not connect. Invocation of ' + action + ' failed. ' + error;
self.debug(msg);
});
return true;
}
When I run my MVC5 app with signalr in Visual Studio everything is fine. After publication to IIS8 on windows Server 2012 it can't connect over web sockets in signal r. I tried to turn off both firewalls for testing but with no success. Can you help me resolve that issue? Of course I read everthing on that page https://learn.microsoft.com/en-us/aspnet/signalr/
In order for SignalR to work properly with WebSocket, you must be sure both client and server support WebSocket. If testing locally works fine, then your browser probably already supports it.
Windows Server 2012 supports SignalR, but you need to be sure websockets feature is enabled:
If this is already enabled, then try recycling your Application Pool (or resetting the IIS).
If recycling/resetting is not sufficient, then you might have something else between the server and the client, like a proxy server or another security layer, like a network firewall (which you might don't have access to it), it could exist in an enterprise environment, or in servers hosted in places like Amazon which might be blocking a port.
I am doing a Chrome Application using the new Socket API (Chrome.sockets.tcp). I have been able to successfully get all HTTP requests working without any issue. The problem that I have run into is the HTTPS login with TLS handshake. We created a Visual Studio C# (RestRequest) application. We are able to connect using HTTPS. Using Wireshark, I notice that the successful communication was achieved using the TLSv1.
I have tried a variety of solutions and referenced/experimented with the below links and tried to come up with a solution.
https://groups.google.com/a/chromium.org/forum/#!msg/net-dev/U2ecAARKvAg/WI1WrSlaOPMJ
SSL Client Authentication with Certificate in Chrome App
Plus many more links! I have written a pile of test applications, but all reach a dead end after the initial handshake.
The following code sequence seems to get the handshake done, but I cannot send the login post. It seems as though the socket is messed up after the handshake. (WireShark shows all com’s were successful up until the login post).
var that = this;
chrome.sockets.tcp.create({
persistent: false,
name: "hc",
bufferSize: 8192
}, function (createInfo) {
console.log("create info = " + JSON.stringify(createInfo));
if (chrome.runtime.lastError) {
error('Unable to create socket: ' + chrome.runtime.lastError.message);
}
that._socketId = createInfo.socketId;
chrome.sockets.tcp.setPaused(that._socketId, true, function () {
chrome.sockets.tcp.connect(that._socketId, that._httpHost, that._httpPort, function (result) {
chrome.sockets.tcp.onReceive.addListener(that._onReceive.bind(this));
chrome.sockets.tcp.onReceiveError.addListener(that._onReceiveError.bind(this));
chrome.sockets.tcp.secure(that._socketId, function (secureResult) {
chrome.sockets.tcp.send(that._socketId, str2ab('POST / HTTP/1.1\r\nHOST: ' + that._httpHost + '\r\n\r\n'), function (sendResult) {});
});
});
});
});
I have tried implementing the TLSSocket from nmp forge and I get the same result as the example above.
We have to use TCP for this application, mainly for cookie support in a Chrome App.
Does anybody have a solution or suggestion? We have put in a lot of hours with trial and error, and seems like we have hit a dead end.
You need to unpause the socket after it's secured. e.g. chrome.sockets.tcp.setPaused(that._socketId, false, ...)