How to send a message with WebSocket to a Socket.io server - javascript

I'm developing a React Native application and I want to use the WebSocket class to communicate with my Socket.io server.
I can connect to the server just fine, but I'm having problems sending messages to it using the .send() method.
I tried this on React Native:
var socket = new WebSocket("ws://host:port/socket.io/?transport=websocket");
socket.onopen = () => {
console.log("connected");
socket.send('data');
};
On my Socket.io server I have this listener that I created just for testing:
socket.on('data', function(data) {
console.log("data");
})
The connection does work, and I'm able to see that on the server too. But when I do socket.send('data') the disconnect event gets called on the server rather than the data event I wrote above. (I tested this by using a function to call the .send() method, so this does cause a disconnect on the server)
Can anyone shine some light on this?

That's because Socket.io is not exactly compatible with WebSocket - there are initial handshakes, connection fallbacks (eg. when no WS is available, use AJAX long pooling or other technique) and other things that Socket.io hides from you to make your life easier. Essentially, Socket.io should be seen as a separate protocol.
To connect to a Socket.io server, you have to use Socket.io client library.

ws.send(`42${ JSON.stringify(["message", { command: "register" }] }`), err => {
if (err) console.log("err", err);
});
This code using the ws pacakge as the example.
You need to add the 42 to tell socoket.io server that you are sending message, the {command: "register"} is the data you send, the "message" is the channel that socket.io is listening on.
io.on("message", (data) => {
console.log(data); // => {command: "register"}
});
Explain: this is the engine.io-protocol that socket.io is using. Check it's spec.
The best solution is using socket.io on both side or don't use socket.io at all.

Related

How to resolve React.js socket.io acknoweldgement timed out?

I have a Node.js and React.js applications, server and client, respectively. I send data between them via socket.io and I am trying to implement acknoledgement but I get an error saying its been timed out:
Error: operation has timed out
at Timeout._onTimeout (C:\Project\gateway\node_modules\socket.io\dist\broadcast-operator.js:137:30)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7)
Here is my server code. Here the message variable prints Error: operation has timed out
socket.emit((topic, message),function(message) {
console.log('GOT MESSAGE');
console.log(message);
});
Here is my client code:
ioClient.on('triton/acs', (data, callback) => {
callback("Message for server")
}
Whhy is this not working and how to fix it?
As #darvine mentioned, there is not a lot of code to see how you implement socket.io server side and client side. However, from what I see above, I'm trying my best to answer your question in broad strokes since I am seeing a few syntax errors.
Your backend code:
socket.emit((topic, message),function(message) {
console.log('GOT MESSAGE');
console.log(message);
});
It appears that you did not establish a connection to the client. You would achieve that by doing the following. Also, socket.emit is sending the data to the client. (There is no callback function in .emit). You send the data as the second parameter. If you want to receive data from the client then you use .on('listener', cb). See below;
//establish connection to the client
io.on('connection', (socket)=> {
//sending a message to the client
socket.emit('yourSentMessage', 'you are sending this message to the client');
//receiving a message from the client.
socket.on('yourReceivedMessage', (msg) => {
console.log(msg) //this message was received from the client
});
});
On the frontend, it is important that you provide your socket instance appropriately. I would utilize context api. See this article for further information on this. You can wrap the components in the provider and have access to the socket instance. Again, it is also important to destinguish between .emit and .on on the frontend. If you want to send data to the backend, you utilize .emit (no callback). If you receive data from the backend, you utilize .on('listener', cb).
Lastly, react requires you to set the proxy server while you are running on localhost. You do that in the package.json file as shown in the screenshot below:

Try to connect to a server with Google Assistance App

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.

SignalR - connect to websocket service from javascript without SignalR library

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}`);
};

Can client know Node.js server has disconnected him

Environment
Server: Node.js
Client: Browser
Communication: Socket.io
I already handle on server side when a client disconnects. But I wonder, is it possible to handle a server disconnection on client side?
Said in other words,
suppose server enters exception state and shuts down, how can the client know this happened? Can I use the very same code
socket.on('disconnect', function() {...});
on client?
Appreciate the help.
Things tried
To check if client is getting notified via
socket.on('disconnect', function() {...});
I throw the following exception in the server:
setTimeout(function () {
console.log('Throwing error now.');
throw new Error('User generated fault.');
}, 9000);
In client I have:
socket.on('disconnect',function(data){ console.log('Server disconnected you'); } );
But the log message in client never happens. ¿?
From the socket.io client docs:
Events
connect. Fired upon connecting.
disconnect. Fired upon a disconnection.
So yes, the client works in identical manner to the server.
Checkout other socket.io client-side events. https://github.com/Automattic/socket.io/wiki/exposed-events
Try to listen 'reconnect_failed' or 'error' instead of 'disconnect'.

Websocket server on Azure with node.js

I'm trying to create a websocket server with Node.js to run on a Windows Azure. This should be simple, but I have run into problems I haven't been able to find solutions for anywhere.
This is my serverside code:
var ws = require('websocket.io')
, http = require('http').createServer().listen(process.env.PORT)
, server = ws.attach(http)
server.on('connection', function (socket) {
socket.on('message', function () { });
socket.on('close', function () { });
});
How do I know which port I need to connect to?
My client code is:
var ws = new WebSocket("ws://socketiopuge.azurewebsites.net");
ws.onopen = function () {
alert("opened");
};
ws.onmessage = function(msg) {
alert(msg);
};
ws.onclose = function () {
alert("closed");
};
When I run the code I get an 501 error code, and the onclode event is fired. I believe the problem is that I need to specify a port number when I create the WebSocket. Can any of you point me in the right direction? Thanks!
About your question "How do I know which port I need to connect to", you would need to create an Input Endpoint and set proper PORT for it. Once you configured it, you will be using the same port in your code to bind and use.
Here is an example about Running socket.io on Windows Azure Web and Worker roles
If you host socket.io in a Windows Azure Web Role, please disable the WebSockets transport on the server because Windows Azure Web role runs on IIS7, web sockets are not supported on IIS7 yet. With Worker Role you dont need to worry about it and you can directly use Web Sockets.
If you're using the new Azure web sites, they do not support websockets yet. The same goes for all web sites hosted through IIS - node.js or not.
Your only way of currently supporting websockets in Azure is by using worker roles and supplying your own node.js executable.

Categories

Resources