I've created a pretty straight forward Java websocket and I'm trying to put it to the test in our test environment. On my local machine, the websocket opens seamlessly, stays with the readystate code '1' and all seems to work well.
On my test machine however, even though the socket appears to open, I still check the readystate and it gives the code '1', the upgrade from Https to websocket happens in the network tab, the OnOpen function in my Java code doesn't seem to get triggered ( I'm trying to log the userId that's coming with the new connection on socket open and that doesn't show either in my test environment logs. On my local machine, that works as well)
private static final ArrayList<Session> connectedSessions = new ArrayList<>();
#OnClose
public void closeSession(Session session) {
try {
connectedSessions.remove(session);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
#OnMessage
public void onMessage(String message, final Session session) {
broadcastMessage(message, session);
}
#OnOpen
public void openSession(#PathParam("userId") String userId, Session session) {
try {
session.getUserProperties().put("USER_ID", userId);
connectedSessions.add(session);
LOGGER.info("-------- Connection id ---------" + userId);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
On the front end I'm using angular, but no other websocket framework, just plain javascript, and for my backend I'm running Xframe 2.2 with Websphere application server 9.0. I'm sure I'm calling the right endpoint since it works on my local machine and I've tested it multiple times with multiple sessions.
EDIT: adding the angular code below
this.ws= new WebSocket("wss://" + env.websocketUrl + "socket" + this.context.settings.userId);
this.ws.onmessage = (event) => {
this.update(event.data, this.context.settings.userId);
};
doSomething(data) {
this.ws.send(data);
}
The thing to note is that the message gets sent. I checked the frames of the WS, but I get no response. It stays "pending"
Can be closed. Turns out my company is blocking any http2 calls that runs on our test/prod servers. It's why websockets were working on my local machine.
Related
I have a react project I am running at http:\\localhost:3000 which connects to ganache running at http:\\localhost:7545.
I deploy a small smart contract onto ganache which increments a counter and emits an event, like this...
// SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
contract Pong {
uint public pong_count;
function ping() public returns (uint){
pong_count++;
emit Pinged(this, pong_count);
return pong_count;
}
event Pinged(Pong indexed me, uint count);
function pong() public returns (uint){
pong_count++;
emit Ponged(this, pong_count);
return pong_count;
}
event Ponged(Pong indexed me, uint count);
}
I want to listen to the Pinged and Ponged events from my contract.
As this is just a helper project for something else I am working on I embed the private key from a ganache account and make an account from it...
var pk_account = w3.eth.accounts.privateKeyToAccount(pk);
Then elsewhere in my code I create an instance of my Pong contract called ponger and store it on a context object in my react app, and invoke the ping() contract method using send like this...
ctx.ponger.methods
.ping()
.send({from:ctx.pk_account.address})
.then((result,err)=>{
if (err){
console.log("pong error: ", err);
}
else {
console.log("pong : ", result);
result.gas = 200000;
ctx.pk_account.signTransaction(result, sent);
}
});
This works like a charm and the local callback sent gets invoked correctly.
I add event listeners to my ponger instance...
function ev_Pong(ev, err){
console.log("got pong event", ev);
}
function ev_Ping(ev, err){
console.log("got ping event", ev);
}
ctx.ponger.events.Pinged(ev_Ping);
ctx.ponger.events.Ponged(ev_Pong);
This is where the fun starts. The message I receive back in ev_Ping is...
got ping event Error: The current provider doesn't support subscriptions: HttpProvider
at subscription.js:176:1
So, duh, I need to use websockets instead of HTTP, right? That means I just connect to ws:\\localhost:7545 instead of http:\\localhost:7545.
(Aside: I do not have any of these issues if I use MetaMask to deliver me web3...)
However I then get a CORS error like this...
Access to XMLHttpRequest at 'ws://localhost:7545/' from origin 'http://localhost:3000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
So my question is how do I overcome the CORS error? I am not sure if this is a ganache question or an old fashioned CORS question, or what.
I don't want to give up on event listening and having to parse through event logs just yet - although I realise there probably is a long route to a different solution.
I figured out what was wrong and it was my fault. The web3 websocket provider does not enforce CORS so it can be used in my use case.
The issue I was having was that even though I change the protocol in the URI I sent web3, I was still asking for an HTTPProvider instead of a WebsocketProvider.
I made a few changes to getWeb3.js for my purposes like this...
const getWeb3 = (url) => {
...
if (url){
if (url.substring(0,2) === 'ws'){
const provider = new Web3.providers.WebsocketProvider(url);
const web3 = new Web3(provider);
console.log("Using WS URL for web3: ", url);
resolve(web3);
}
else {
const provider = new Web3.providers.HttpProvider(url);
const web3 = new Web3(provider);
console.log("Using HTTP URL for web3: ", url);
resolve(web3);
}
}
...
}
This worked fine.
On the plus side it made me understand CORS a lot better. I really don't like disabling anything in the browser.
I wrote a program in c++ to upgrade an HTTP session to a WebSocket. The server correctly receives the upgrade request, and responds with 101 switching protocols. Firefox receives the 101 response, but in the console claims it couldn't connect. Here's the full output in Firefox.
The interesting thing is, in the network tab you can see the 101 response come in so it did establish an HTTP connection, the server got it, accepted it, tried to upgrade, and sent an upgrade response, but it's at that point that firefox doesn't upgrade to a WebSocket and prints the error.
I tried in Google Chrome as well. Similar error, but a bit more detail. WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
My code c++ hangs on the while loop, no errors thrown, which I think means it thinks the connection is still working?
I did notice it's sending Sec-Websocket-Protocol, even though I only asked for ws, not wss. Do chrome and firefox disallow non secure websockets? Or am I missing something in my code?
C++:
#define PORT (unsigned short) 3000
#define MAX_BUF 2048
int main()
{
Poco::Net::ServerSocket x(PORT);
Poco::Timespan timeout(25000000);
if (x.poll(timeout, 1)) {
Poco::Net::StreamSocket ss = x.acceptConnection();
Poco::AutoPtr<Poco::Net::HTTPServerParams> params = new Poco::Net::HTTPServerParams();
Poco::Net::HTTPServerSession sess(ss,params);
Poco::Net::HTTPServerResponseImpl res(sess);
Poco::Net::HTTPServerRequestImpl req(res, sess, params);
if (req.getMethod()=="GET" && req.get("Upgrade")=="websocket") {
Poco::Net::WebSocket webSock(req,res);
while (!webSock.available());
char buf[MAX_BUF];
memset(buf,0,MAX_BUF);
int flags = 0;
webSock.sendFrame("Hello, World!\n",15);
webSock.receiveFrame(buf,MAX_BUF,flags);
printf("received %s\n",buf);
}
}
else {
printf("Timeout!\n");
}
return 0;
}
Javascript:
$(document).ready(function() {
webSoc = new WebSocket("ws://localhost:3000");
webSoc.onopen = function (event) {
$("#c").click(function () {
console.log("Sending 'Hello, World!'");
webSoc.send("Hello, World!\n");
});
}
});
I've tried new WebSocket("ws://localhost:3000") with and without the echo-protocol parameter, because I read it in an answer to a question I didn't understand, which I can't find now.
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.
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).
I wrote a chat through WebSockets.
Server side is written in Java (Tomcat) and client in JavaScript.
All works fine. But when I try connect to server from two machines which are in local network (they're under router; have one external ip) only one client receives data from server.
Connection ( socket.onopen() ) works for both. socket.send(data) also works on both clients;
But receiving messages ( socket.onmessage() ) works just on first connected client.
How can I resolve this problem?
Problem was in server part.
I wanted to broadcast incoming message to all available connections which were in ArrayList.
After sending message to first user, received message became emptied. So, message was sent, but it was just empty string.
My english is bad. So I will whow :
before :
protected void onTextMessage(CharBuffer message) throws IOException {
// List<MessageInbound> connections
for (MessageInbound user : connections )
user.getWsOutbound.writeTextMessage(message);
}
after:
protected void onTextMessage(CharBuffer message) throws IOException {
String msg = message.toString();
for (MessageInbound user : connections )
user.getWsOutbound.writeTextMessage(CharBuffer.wrap(msg));
}