Visión general de la API
Antes de continuar, hagamos un recorrido rápido por la API proporcionada por Socket.IO:
API común
Los siguientes métodos están disponibles tanto para el cliente como para el servidor.
Emit básico
Como vimos en el paso #4, puedes enviar cualquier dato al otro lado con socket.emit():
- Del cliente al servidor
- Del servidor al cliente
Cliente
socket.emit('hello', 'world');
Servidor
io.on('connection', (socket) => {
socket.on('hello', (arg) => {
console.log(arg); // 'world'
});
});
Servidor
io.on('connection', (socket) => {
socket.emit('hello', 'world');
});
Cliente
socket.on('hello', (arg) => {
console.log(arg); // 'world'
});
Puedes enviar cualquier número de argumentos, y todas las estructuras de datos serializables son soportadas, incluyendo objetos binarios como ArrayBuffer, TypedArray o Buffer (solo Node.js):
- Del cliente al servidor
- Del servidor al cliente
Cliente
socket.emit('hello', 1, '2', { 3: '4', 5: Uint8Array.from([6]) });
Servidor
io.on('connection', (socket) => {
socket.on('hello', (arg1, arg2, arg3) => {
console.log(arg1); // 1
console.log(arg2); // '2'
console.log(arg3); // { 3: '4', 5: <Buffer 06> }
});
});
Servidor
io.on('connection', (socket) => {
socket.emit('hello', 1, '2', { 3: '4', 5: Buffer.from([6]) });
});
Cliente
socket.on('hello', (arg1, arg2, arg3) => {
console.log(arg1); // 1
console.log(arg2); // '2'
console.log(arg3); // { 3: '4', 5: ArrayBuffer (1) [ 6 ] }
});
No es necesario llamar JSON.stringify() en objetos:
// MAL
socket.emit('hello', JSON.stringify({ name: 'John' }));
// BIEN
socket.emit('hello', { name: 'John' });
Acknowledgements
Los eventos son geniales, pero en algunos casos puedes querer una API de solicitud-respuesta más clásica. En Socket.IO, esta característica se llama "acknowledgements".
Viene en dos sabores:
Con una función callback
Puedes añadir un callback como el último argumento del emit(), y este callback será llamado una vez que el otro lado haya reconocido el evento:
- Del cliente al servidor
- Del servidor al cliente
Cliente
socket.timeout(5000).emit('request', { foo: 'bar' }, 'baz', (err, response) => {
if (err) {
// el servidor no reconoció el evento en el tiempo dado
} else {
console.log(response.status); // 'ok'
}
});
Servidor
io.on('connection', (socket) => {
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
});
Servidor
io.on('connection', (socket) => {
socket.timeout(5000).emit('request', { foo: 'bar' }, 'baz', (err, response) => {
if (err) {
// el cliente no reconoció el evento en el tiempo dado
} else {
console.log(response.status); // 'ok'
}
});
});
Cliente
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
Con una Promise
El método emitWithAck() proporciona la misma funcionalidad, pero devuelve una Promise que se resolverá una vez que el otro lado reconozca el evento:
- Del cliente al servidor
- Del servidor al cliente
Cliente
try {
const response = await socket.timeout(5000).emitWithAck('request', { foo: 'bar' }, 'baz');
console.log(response.status); // 'ok'
} catch (e) {
// el servidor no reconoció el evento en el tiempo dado
}
Servidor
io.on('connection', (socket) => {
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
});
Servidor
io.on('connection', async (socket) => {
try {
const response = await socket.timeout(5000).emitWithAck('request', { foo: 'bar' }, 'baz');
console.log(response.status); // 'ok'
} catch (e) {
// el cliente no reconoció el evento en el tiempo dado
}
});
Cliente
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
Los entornos que no soportan Promises (como Internet Explorer) necesitarán añadir un polyfill o usar un compilador como babel para usar esta característica (pero esto está fuera del alcance de este tutorial).
Listeners catch-all
Un listener catch-all es un listener que será llamado para cualquier evento entrante. Esto es útil para depurar tu aplicación:
Emisor
socket.emit('hello', 1, '2', { 3: '4', 5: Uint8Array.from([6]) });
Receptor
socket.onAny((eventName, ...args) => {
console.log(eventName); // 'hello'
console.log(args); // [ 1, '2', { 3: '4', 5: ArrayBuffer (1) [ 6 ] } ]
});
De manera similar, para paquetes salientes:
socket.onAnyOutgoing((eventName, ...args) => {
console.log(eventName); // 'hello'
console.log(args); // [ 1, '2', { 3: '4', 5: ArrayBuffer (1) [ 6 ] } ]
});
API del servidor
Broadcasting
Como vimos en el paso #5, puedes difundir un evento a todos los clientes conectados con io.emit():
io.emit('hello', 'world');


Rooms
En la jerga de Socket.IO, una room es un canal arbitrario al que los sockets pueden unirse y abandonar. Se puede usar para difundir eventos a un subconjunto de clientes conectados:
io.on('connection', (socket) => {
// unirse a la sala llamada 'some room'
socket.join('some room');
// difundir a todos los clientes conectados en la sala
io.to('some room').emit('hello', 'world');
// difundir a todos los clientes conectados excepto los de la sala
io.except('some room').emit('hello', 'world');
// abandonar la sala
socket.leave('some room');
});


¡Eso es básicamente todo! Para referencia futura, la API completa se puede encontrar aquí (servidor) y aquí (cliente).