My reactjs app creates a socket.io connection to nodejs. Using socket.io 4.1.2 and I can see it in connection event on server side as follows;
const io = new Server(server);
io.on("connection", async (socket: Socket) => {
console.log("CONNECTION...", socket.id);
socket.onAny((event, ...args) => {
console.log(`ANY ${event}`, socket.id);
});
});
AFAIK, we can catch any event on server side. However, socket.onAny never gets hit by any event after connection. For example, when I close the browser, I saw below lines on server side. But any did not catch this disconnect event.
socket.io:client client close with reason transport error +6m
socket.io:socket closing socket - reason transport error +6m
socket.io:client client close with reason transport close +1s
socket.io:socket closing socket - reason transport close +1s
How can I catch all the events on server side?
I know it's not stated in the documentation but I think onAny listener only counts for events "manually" emitted from the client socket. Like :
// client
socket.emit("some-event");
// server
socket.onAny((event) => {
console.log(`ANY $[event}`);
});
// will log "ANY some-event"
However, for the disconnect event you would need an additional listener, like:
// server
socket.on("disconnect", (reason) => {
// ...
});
Try emitting a few events from your client side and check if your onAny listener gets triggered. It should !
Related
I am trying to make a game server with node.js, socket.io.
The basic idea likes below.
Initialize socket.io instance when the server starts
Store instance in global scope, so controllers can access it
When API calls, we trigger some socket.io event in the controller or some other points
Here is the implementation I made ...
First, in server.js - entry point
let GlobalVars = require('./state/GlobalVars');
const apiRouters = require('./router');
...
app.use('/api', apiRouters);
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/test/simpleClient.html`)
});
const httpServer = http.createServer(app);
let socketIOInstance = socketIO(httpServer);
socketIOInstance.on('connection', (socket) => {
console.log('SOCKET.IO A USER CONNECTED');
socket.on('create', (data) => {
console.log('SOCKET.IO create called', socket);
socket.join(data.room);
socketIOInstance.emit('message', 'New people joined');
});
socket.on('join', (data) => {
console.log('SOCKET.IO join called', data);
})
socket.emit('message', 'Hi');
});
GlobalVars.socketIO = socketIOInstance;
// Add to global, so the controllers can manage own actions like create, join ...
httpServer.listen(port, () => {
console.log(`Server Listening on the port ${port}`);
})
...
When I access from a client, I am able to see SOCKET.IO A USER CONNECTED and Hi in the browser console.
Second, In api controller.
let GlobalVars = require('../state/GlobalVars');
...
router.post('/create', (req, res) => {
console.log('GenerateGameSokect');
let game = new Game();
let gameId = game.gameId;
// console.log('Global vars ', GlobalVars.socketIO);
GlobalVars.socketIO.emit('create', {
room: gameId
});
res.json({
result : 'SUCCESS',
game : game
})
});
I imported GlobalVars which contains socketIO instance. So what I expected was, socket create event triggered from the statement GlobalVars.socketIO.emit('create', Object) but could not find message in the server logs.
I got no clue what I was missing.
The final form I pursue is something like...
When user call create API, I creates socket connection and room
API will called in HTTP protocol, but in the API, the server publishes some events. - pubsub like.
Thanks for reading my questions b. Here is full source code till now(bitbucket public)
================== EDIT ====================
I got understood (maybe...)
The user-flow I wanted was ...
The client call API
(In the server) Checking validation in API and if valid emit to socket.io
If event accepted send new status to all clients
However, creating socket.io connection in the server looks strange for me, the solution is up to the client.
New user-flow I will change
The client call a validation API
If return is valid, the client emit socket.io event. This time server only do validation, not emit socket.io
In socket event, send new status to all other users
================== EDIT #2 ====================
This is a kind of conclusion. It looks I just misunderstanding the concept of socket communication. Like answer and replies say, Socket and HTTP are totally different channels, there is no way to connect both. (At least, without open new connection from http server to socket)
If this is wrong, you could add reply, Thanks
Now I understand you. Or at least I think!
Let's put it this way: there are two (asymetric) sides on a socket, server and client. What I called, respectively, "global manager" and "socket" in my comment to your post.
const server = require('socket.io')(yourHttpServer);
// client is installed as well when `npm i socket.io`
const client = require('socket.io-client')('http://localhost:' + yourServerPort);
// `socket` is the server side of the socket
server.on('connection', (socket) => {
// this will be triggered by client sides emitting 'create'
socket.on('create', (data) => {
console.log('a client socket just fired a "create" event!');
});
});
// this will be triggered by server side emitting 'create'
client.on('create', (data) => {
server.emit('create', {content: 'this will result in an infinite loop of "create" events!'});
});
In your /create route, when you GlobalVars.socketIO.emit('create', ...), the server-side socket handler isn't triggered, however if you have clients connected through a browser (or, like I showed above, if you connect a client socket directly from the server) then these will trigger their 'create' listener, if any.
Hope this helps you get on the right tracks!
so I am developing an small application that need a bi-directional channel to transmit data between client and server.
I have no problem to send sata from server to client. Works just fine. But , the other way around is not working. for some reason , sending data from client to client does not work.
here is the client.js
let io = require('socket.io-client');
let socket = io.connect("http://localhost:5000/", {
reconnection: false
});
socket.on('connect', function() {
console.log('Connected to server');
socket.emit('data', 'data is emitted !')
});
and here is server.js :
var io = require('socket.io').listen(process.env.port||5000);
io.on('connection',function () {
console.log('client connected');
io.on('data',function (data) {
console.log(`data received is '${data}'`)
})
});
What am I missing ?
The server code needs to listen for incoming events from a particular socket.on(), not io.on(). io is the server. It gets notified of new connections, but not of individual messages on a given connection. You have to listen to events on a particular socket to receive data from the client.
So, change to this (change io to socket in one place and add socket argument to the io.on('connection', function(socket) ()); handler (see the two places that socket was added below):
const io = require('socket.io').listen(process.env.port||5000);
io.on('connection', function(socket) {
console.log('client connected');
// listen for incoming data msg on this newly connected socket
socket.on('data',function (data) {
console.log(`data received is '${data}'`)
});
});
Note: the addition of socket in two places.
I'm using "socket.io": "1.4.5","socket.io-redis": "1.0.0". The javascript client using socket-io-client seems to be happily connecting to the server except for when the server is restarted. The connection attempt fails triggering 'connect_error' event with message '{"message":"xhr poll error", "type":"TransportError","description":0"}'. If I restart by browser the connection works just fine. I also noticed that if I set a breakpoint in event handler for 'connect_error' and wait for a few seconds it the connection attempt succeeds eventually. I'm missing something a config setting in client code? here is the client code I have
var socketConnectParams = {'max reconnection attempts': 150};
socketConnectParams['reconnection'] = true;
socketConnectParams['reconnectionDelay'] = 5000;
socketConnectParams['reconnectionDelayMax'] = 15000;
var socket = io('http://localhost:8888', socketConnectParams);
socket.on('connect', function () { });
socket.on('connect_error', function(error) {
dLog("connection error event received." + JSON.stringify(error));
});
I listen to a "disconnect" event to rebind a new 'connect' event. This way, if you server is restarted, the local client will detect this and create a new listener for then the server comes up again. Maybe you could try that.
socket.on('disconnect', function(){
socketCleanup(); // this is a function to cleanup all listeners, just in case, so you can restart fresh
socket.on('connect', function(){
socketConnect();
});
});
I am not sure I understand the server side configuration of the socket.
var app = express();
var server = require('http').createServer(app);
var socketio = require('socket.io')(server, {
serveClient: config.env !== 'production',
path: '/socket.io-client'
});
Here, the code creates a socket server "attached" with the http server according to the api reference. What is attach?
socketio.on('connection', function (socket) {
socket.on('create', function(room) {
console.log('joining a room');
socket.join(room);
console.log('socket joined room: ', room);
});
socket.address = socket.handshake.address !== null ?
socket.handshake.address.address + ':' + socket.handshake.address.port :
process.env.DOMAIN;
socket.connectedAt = new Date();
// Call onDisconnect.
socket.on('disconnect', function () {
onDisconnect(socket);
console.info('[%s] DISCONNECTED', socket.address);
});
// Call onConnect.
onConnect(socket);
console.info('[%s] CONNECTED', socket.address);
});
};
Question: Here, the 'socket' variable is server's or client's ? if it is server's then why the socket.join(room) works ? (client's been added to a room) If it is client's, then why it has to listen to 'create' event.(client emits an event called create to change the room.)
to conclude, I confused by the three 'socket' in the following code.
socketio.on('connection', function (socket) {
socket.on('create', function(room) {
console.log('joining a room');
socket.join(room);
console.log('socket joined room: ', room);
});
});
Here, the code creates a socket server "attached" with the http server according to the api reference. What is attach?
webSocket connections (which socket.io is built on top of) all get initiated from the client by first making an HTTP connection. Thus, there must be an HTTP server that can be used for socket.io connections. That's why the initialization of socket.io needs an HTTP connection. Often, that web server is also acting as a normal web server too and thus can be used for both purposes. This simplifies cross-origin issues since all browsers all clients to connect to the same origin from which their web page was served. If, you don't already have another web server, socket.io can create it's own.
Question: Here, the 'socket' variable is server's or client's ?
It is the server-side object that represents the connection to a particular client. Socket.io has a socket object on the client that represents the client-side connection to the server and it has a socket object on the server (for each separate client connection) that represents the connection to a particular client.
So, if you want to send data to a particular client, you use the socket object that represents that client and you do:
socket.emit(msg, data);
if it is server's then why the socket.join(room) works ?
This works because this socket object represents the connection to a particular client. It is a server-side object, but it is specific to a particular client (e.g. there's a different one for each client connection).
to conclude, I confused by the three 'socket' in the following code.
socketio.on('connection', function (socket) {
socket.on('create', function(room) {
console.log('joining a room');
socket.join(room);
console.log('socket joined room: ', room);
});
});
socketio represents the overall socket.io module and is how you execute global commands. In this case, you are executing a global command to listen for any newly connection clients.
When you get a connection event, the argument to that event is the newly created socket object (a server-side object that represents a connection to a particular client).
The socket.on('create', ...) is a listener for the create message sent from the client to the server. So, this line of code says to listen for a create message sent from this particular (newly connected) client and when that message arrives, call a callback and pass it the data sent with the message (in this case a room name).
The socket.join(room); line uses the same socket as above and joins it to a specific room on the server.
i am new to socket.io. i want to notify user when the internet connection drops
or failed to connect to the server in socket.io. in client pc if we drop the internet connection, socket.io makes xhr pooling to connect to the server. My intention is to notify the user when ever the connection drops or server is down and client failed to connect it.
The following code is of client side socket.io app, but following events never fires when ever internet connection failed or server is down.
var socket = io('http://192.168.1.109:3000');
socket.on("private msg", function (data) {
console.log(data.msg);
});
socket.on("conect_error", function (data) {
console.log("connect)error");
// this event never fires
});
socket.on("connect_timeout",function(){
console.log("connection timeout");
//this event never fires
});
socket.on("reconnect", function () {
console.log("reconnected");
// this works fine
});
socket.on("disconnect",function(){
console.log("disconnected");
// this works fine
});