Java Socket and JS WebSocket - javascript

So I am trying to make some sort of connection between my Java app and my Web app, I looked up websockets and they look really simple and easy to use :). And I created myself a Java Server, which uses the ServerSocket class.
Now the problem is I am able to connect to the server from the web, with the websocket, but I am unable to send data to the server... but when I tried to send data from a Java Client it worked fine... what might be the problem?
My Java/Scala (I followed this tutorial: https://www.tutorialspoint.com/java/java_networking.htm) server:
class Server(val port: Int) extends Thread {
private val serverSocket = new ServerSocket(port)
override def run(): Unit = {
try {
while(true) {
println("Waiting for client on port: " + serverSocket.getLocalPort)
val server = serverSocket.accept()
println(server.getRemoteSocketAddress)
val in = new DataInputStream(server.getInputStream())
println(in.readUTF())
val out = new DataOutputStream(server.getOutputStream())
out.writeUTF("Hello world!")
server.close()
}
} catch {
case s: SocketTimeoutException => println("Connection timed out!");
case e: Exception => e.printStackTrace()
}
}
}
My web js (I followed https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications ):
/**
* Created by samuelkodytek on 20/12/2016.
*/
var conn = new WebSocket('ws://127.0.0.1:8080');
conn.onopen = function(e) {
console.log("Connection established!");
conn.send("Hello!");
};
conn.onmessage = function(e) {
console.log(e.data);
};

A web socket server is not the same thing as a simple socket server. A server that offers web sockets must first offer HTTP or HTTPS services because the web socket is established when a web client sends an HTTP request with an Upgrade option and special fields for establishing the web socket. Even after the web socket is established, the connection still does not behave exactly like a regular socket. The Web Socket protocol uses frames to send or receive data. This is all considerably different from what you seem to expect.
One other thing that you should be aware of is that the browser will enforce the rule that the web socket must come from the same host as the page that is attempting to establish the web socket (the same protocol, address, and TCP port).

Related

SocketIO message originated from the server is not working

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.

Connecting client to socket in Angularjs

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.

Send XMPP notification from Node.js script

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.

standalone nodejs client connects to a self signed websocket (wss)

I have a node server (Meteor.js) that should communicate with another server using websockets.
As the communication is between servers that don't involve direct users, I've chosen to use a self signed certificate.
Where to add the certificate parameters from the node server (which is a client to the other server)
var soc = new WebSocket("wss://localhost:9000")
I've tested connecting in insecure mode with certification and it works fine.
var soc = new WebSocket("ws://localhost:9000")
Connecting from android application in secure mode after adding the certificates to the application works fine too.
I've found this solution, the part that allows the client to connect to a secure socket with a self-signed certificate is:
"rejectUnauthorized: false"
It accepts all certificates but it still keeps the connection encrypted.
'use strict';
var WebSocket = require('ws');
var soc = new WebSocket("wss://localhost:9000", {
protocolVersion: 8,
origin: 'https://localhost:9000',
rejectUnauthorized: false
});
console.log("launched");
soc.onopen = function (event) {
console.log("Sending message");
soc.send('{}');
};
soc.onmessage = function (event) {
console.log(event.data);
}
soc.on('error', function(event) {
console.log(event);
});

Using an IP address parameter in the creation of a Socket.io socket

In the following snippet, a tutorial author shows how to alter the original tutorial to include an http server. Here's the snippet.
var http = require(‘http’),
fs = require(‘fs’),
io = require(‘socket.io’),
index;
fs.readFile(‘./chat.html’, function (err, data) {
if (err) {
throw err;
}
index = data;
});
var server = http.createServer(function(request, response) {
response.writeHeader(200, {“Content-Type”: “text/html”});
response.write(index);
response.end();
}).listen(1223);
//and replace var socket = io.listen(1223, "1.2.3.4"); with:
var socket = io.listen(server);
The code in the original tutorial didn't include the http server, and socket was defined as simply:
var socket = io.listen(1223, "1.2.3.4");
I noticed that he replaces the variable's content io.listen(1223, "1.2.3.4"); with server which doesn't include the ip (1.2.3.4) anywhere.
My Question:
What is the purpose/effect of the referenced IP address?
Why is it excluded when passing an http server to create the socket?
When you are listening on a port, you can optionally include the IP address of a specific interface to listen on. For example, you might have several network interfaces with several IP addresses, and only want your service running on one of them. A more common use case is that you only want your server accessible on localhost, so you might have it listen only on 127.0.0.1.
Now, when you call io.listen(server) where server is an existing Node.js HTTP server, Socket.IO isn't actually opening a new listening connection at all. This is a shortcut for Socket.IO to wrap its methods on the existing HTTP server. If you wanted to specify a specific interface address to listen on, you would need to do it where .listen() is called on the HTTP server, above where you call io.listen(server).
More info in the documentation for raw network sockets in Node.js: http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback

Categories