Socket.io : Event-based communication

更新时间:
2024-05-15
下载文档

Socket.io : Event-based communication

Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server. It consists of:

  • Server module.
  • A Javascript client library for the browser.

This document is mainly about the server. Its main features are:

Support

The following shows socket.io module APIs available for each permissions.

 User ModePrivilege Mode
server.sockets
server.serveClient
server.path
server.origins
server.attach
server.bind
server.onconnection
server.of
server.close
server.engine.generateId
namespace.name
namespace.connected
namespace.to
namespace.in
namespace.emit
namespace.clients
namespace.use
socket.id
socket.rooms
socket.client
socket.conn
socket.request
socket.handshake
socket.remoteAddress
socket.use
socket.send
socket.emit
socket.on
socket.once
socket.removeListener
socket.removeAllListeners
socket.eventNames
socket.join
socket.leave
socket.to
socket.in
socket.compress
socket.disconnect
client.conn
client.request

Server

Exposed by require('socket.io').

new Server(server[, options])

  • server {HttpServer | WebApp} The server to bind to.
  • options {Object}
    • path {String} Name of the path to capture (/socket.io)
    • serveClient {Boolean} Whether to serve the client files (true)
    • adapter {Adapter} The adapter to use. default: an instance of the Adapter that ships with socket.io which is memory based.
    • origins {String} The allowed origins (*)
    • parser {Parser} The parser to use. default: an instance of the Parser That ships with socket.io.

Among those options:

  • pingTimeout {Integer} How many ms without a pong packet to consider the connection closed (60000)
  • pingInterval {Integer} How many ms before sending a new ping packet (25000).

Those two parameters will impact the delay before a client knows the server is not available anymore. For example, if the underlying TCP connection is not closed properly due to a network issue, a client may have to wait up to pingTimeout + pingInterval ms before getting a disconnect event.

  • transports {Array[String]} Transports to allow connections to. default: ['polling', 'websocket'].

Example

var server = http.createServer('./test', handle, 0, socket.sockaddr(socket.INADDR_ANY, 8000));

var io = require('socket.io')(server, {
  path: '/test',
  serveClient: false,
  pingInterval: 10000,
  pingTimeout: 5000,
  cookie: false
});

server.start();

server.sockets

  • {Namespace} Namespace default: (/).

server.serveClient([value])

  • value {Boolean} default: true.
  • Returns {Server | Boolean}

If value is true the attached server (see server.attach()) will serve the client files. Default: true. This method has no effect after attach is called. If no arguments are supplied this method returns the current value.

Example

// pass a server and the `serveClient` option
var io = require('socket.io')(http, { serveClient: false });

server.path([value])

  • value {String}
  • Returns {Server | String}

Sets the path value under which engine.io and the static files will be served. Default: /socket.io. If no arguments are supplied this method returns the current value.

Example

var io = require('socket.io')(http);
io.path('/myownpath');

// client-side
var socket = io(http, {
  path: '/myownpath'
});

server.origins([value])

  • value {String | String[]}
  • Returns {Server | String}

Sets the allowed origins value. Defaults to any origins being allowed. If no arguments are supplied this method returns the current value.

Example

io.origins(['https://foo.example.com:443']);

server.origins(fn)

  • fn {Function}
  • Returns {Server}

Provides a function taking two arguments origin:String and callback(error, success), where success is a boolean value indicating whether origin is allowed or not. If success is set to false, error must be provided as a string value that will be appended to the server response, e.g. "Origin not allowed".

Potential drawbacks:

  • in some situations, when it is not possible to determine origin it may have value of *
  • As this function will be executed for every request, it is advised to make this function work as fast as possible

Example

io.origins((origin, callback) => {
  if (origin !== 'https://foo.example.com') {
    return callback('origin not allowed', false);
  }
  callback(null, true);
});

server.attach(server[, options])

  • httpServer {httpServer | WebApp} The server to attach to
  • options {Object}

Attaches the Server to an engine.io instance on server with the supplied options (optionally).

server.bind(engine)

  • engine {engine.Server}
  • Returns {Server}

Advanced use only. Binds the server to a specific engine.io Server (or compatible API) instance.

server.onconnection(socket)

  • socket {engine.Socket}
  • Returns {Server}

Advanced use only. Creates a new socket.io client from the incoming engine.io (or compatible API) Socket.

server.of(nsp)

  • nsp {String | Function}
  • Returns {Namespace}

Initializes and retrieves the given Namespace by its pathname identifier nsp. If the namespace was already initialized it returns it immediately.

Example

var adminNamespace = io.of('/admin');

A regex or a function can also be provided, in order to create namespace in a dynamic way:

var dynamicNsp = io.of(/^\/dynamic-\d+$/).on('connect', (socket) => {
  var newNamespace = socket.nsp; // newNamespace.name === '/dynamic-101'

  // broadcast to all clients in the given sub-namespace
  newNamespace.emit('hello');
});

// client-side
var socket = io('/dynamic-101');

// broadcast to all clients in each sub-namespace
dynamicNsp.emit('hello');

// use a middleware for each sub-namespace
dynamicNsp.use((socket, next) => { /* ... */ });

With a function:

io.of((name, query, next) => {
  next(null, checkToken(query.token));
}).on('connect', (socket) => { /* ... */ });

server.close([callback])

  • callback {Function}

Closes the socket.io server. The callback argument is optional and will be called when all connections are closed.

server.engine.generateId

Overwrites the default method to generate your custom socket id.

Example

io.engine.generateId = (req) => {
  return "custom:id:" + custom_id++; // custom id must be unique
}

Namespace

Represents a pool of sockets connected under a given scope identified by a pathname (eg: /chat).

A client always connects to / (the main namespace), then potentially connect to other namespaces (while using the same underlying connection).

namespace.name

  • {String}

The namespace identifier property.

namespace.connected

  • {Socket} socket.io Socket object.

The hash of Socket objects that are connected to this namespace, indexed by id.

namespace.to(room)

  • room {String}
  • Returns {Namespace} For chaining

Sets a modifier for a subsequent event emission that the event will only be broadcasted to clients that have joined the given room.

To emit to multiple rooms, you can call to several times.

Example

var io = require('socket.io')(http);
var adminNamespace = io.of('/admin');

adminNamespace.to('level1').emit('an event', { some: 'data' });

namespace.in(room)

Synonym of namespace.to(room).

namespace.emit(eventName[, ...args])

  • eventName {String}
  • args

Emits an event to all connected clients. The following two are equivalent:

Example

var io = require('socket.io')(http);
io.emit('an event sent to all connected clients'); // main namespace

var chat = io.of('/chat');
chat.emit('an event sent to all connected clients in chat namespace');

namespace.clients(callback)

  • callback {Function}
    • error {Error} Error object.
    • clients {Array} A list of Client object.

Gets a list of client IDs connected to this namespace (across all nodes if applicable).

Example

var io = require('socket.io')(http);
io.of('/chat').clients((error, clients) => {
  if (error) throw error;
  console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
});

An example to get all clients in namespace's room:

io.of('/chat').in('general').clients((error, clients) => {
  if (error) throw error;
  console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
});

As with broadcasting, the default is all clients from the default namespace ('/'):

io.clients((error, clients) => {
  if (error) throw error;
  console.log(clients); // => [6em3d4TJP8Et9EMNAAAA, G5p55dHhGgUnLUctAAAB]
});

namespace.use(fn)

  • fn {Function}

Registers a middleware, which is a function that gets executed for every incoming Socket, and receives as parameters the socket and a function to optionally defer execution to the next registered middleware.

Errors passed to middleware callbacks are sent as special error packets to clients.

Example

io.use((socket, next) => {
  if (socket.request.headers.cookie) return next();
  next(new Error('Authentication error'));
});

Event: 'connect'

  • socket {Socket} Socket connection with client

Fired upon a connection from client.

Example

io.on('connect', (socket) => {
  // ...
});

io.of('/admin').on('connect', (socket) => {
  // ...
});

Event: 'connection'

Synonym of event: connect.

Flag: 'volatile'

Sets a modifier for a subsequent event emission that the event data may be lost if the clients are not ready to receive messages (because of network slowness or other issues, or because they’re connected through long polling and is in the middle of a request-response cycle).

Example

io.volatile.emit('an event', { some: 'data' }); // the clients may or may not receive it

Flag: 'binary'

Specifies whether there is binary data in the emitted data. Increases performance when specified. Can be true or false.

Example

io.binary(false).emit('an event', { some: 'data' });

Flag: 'local'

Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.

Example

io.local.emit('an event', { some: 'data' });

Socket

A Socket is the fundamental class for interacting with browser clients. A Socket belongs to a certain Namespace (by default: /) and uses an underlying Client to communicate.

It should be noted the Socket doesn't relate directly to the actual underlying TCP/IP socket and it is only the name of the class.

Within each Namespace, you can also define arbitrary channels (called room) that the Socket can join and leave. That provides a convenient way to broadcast to a group of Sockets (see Socket#to below).

The Socket class inherits from EventEmitter. The Socket class overrides the emit method, and does not modify any other EventEmitter method. All methods documented here which also appear as EventEmitter methods (apart from emit) are implemented by EventEmitter, and documentation for EventEmitter applies.

socket.id

  • {String}

A unique identifier for the session, that comes from the underlying Client.

socket.rooms

  • {Object}

A hash of strings identifying the rooms this client is in, indexed by room name.

Example

io.on('connection', (socket) => {
  socket.join('room 237', () => {
    var rooms = Object.keys(socket.rooms);
    console.log(rooms); // [ <socket.id>, 'room 237' ]
  });
});

socket.client

  • {Client}

A reference to the underlying Client object.

socket.conn

  • {engine.Socket}

A reference to the underlying Client transport connection (engine.io Socket object). This allows access to the IO transport layer, which still (mostly) abstracts the actual TCP/IP socket.

socket.request

  • {Request}

A getter proxy that returns the reference to the request that originated the underlying engine.io Client. Useful for accessing request headers such as Cookie or User-Agent.

socket.handshake

  • {Object}

The handshake details:

Example

{
  eos: /* EdgerOS handshake information */,
  headers: /* the headers sent as part of the handshake */,
  time: /* the date of creation (as string) */,
  address: /* the ip of the client */,
  xdomain: /* whether the connection is cross-domain */,
  secure: /* whether the connection is secure */,
  issued: /* the date of creation (as unix timestamp) */,
  url: /* the request URL string */,
  query: /* the query object */
}

Usage:

io.use((socket, next) => {
  var handshake = socket.handshake;
  // ...
});

io.on('connection', (socket) => {
  var handshake = socket.handshake;
  // ...
});
io.on('connection', (socket) => {
  var handshake = socket.handshake;
  var user = handshake.eos.user;
  if (user) {
    console.log(user.acoid, user.nickname);
  }
});

User information includes:

  • acoid {String} EdgerOS user unique ID, also known as acoinfo ID.
  • nickname {String} Nickname of this user.

See eos middleware for details.

socket.remoteAddress

  • {String | Undefined}

Get remote address.

Example

console.log(socket.remoteAddress); // 127.0.0.1

socket.use(fn)

  • fn {Function}

Registers a middleware, which is a function that gets executed for every incoming Packet and receives as parameter the packet and a function to optionally defer execution to the next registered middleware.

Errors passed to middleware callbacks are sent as special error packets to clients.

Example

io.on('connection', (socket) => {
  socket.use((packet, next) => {
    if (packet.doge === true) return next();
    next(new Error('Not a doge error'));
  });
});

socket.send([...args][, ack])

  • args
  • ack {Function}
  • Returns {Socket}

Sends a message event. See socket.emit(eventName[, ...args][, ack])

socket.emit(eventName[, ...args][, ack])

  • (overrides EventEmitter.emit)*
    • eventName {String}
    • args
    • ack {Function}
    • Returns {Socket}

Emits an event to the socket identified by the string name. Any other parameters can be included. All serializable datastructures are supported, including Buffer.

Example

socket.emit('hello', 'world');
socket.emit('with-binary', 1, '2', { 3: '4', 5: new Buffer(6) });

The ack argument is optional and will be called with the client's answer.

io.on('connection', (socket) => {
  socket.emit('an event', { some: 'data' });

  socket.emit('ferret', 'tobi', (data) => {
  console.log(data); // data will be 'woot'
  });

  // the client code
  // client.on('ferret', (name, fn) => {
  //   fn('woot');
  // });
});

socket.on(eventName, callback)

  • (inherited from EventEmitter)*
  • eventName {String}
  • callback {Function} With arguments from cliet.
  • Returns {Socket}

Register a new handler for the given event.

Example

socket.on('news', (data) => {
  console.log(data);
});
// with several arguments
socket.on('news', (arg1, arg2, arg3) => {
  // ...
});
// or with acknowledgement
socket.on('news', (data, callback) => {
  callback(0);
});

socket.once(eventName, listener)

socket.removeListener(eventName, listener)

socket.removeAllListeners([eventName])

socket.eventNames()

Inherited from EventEmitter (along with other methods not mentioned here). See Node.js documentation for the events module.

socket.join(room[, callback])

  • room {String}
  • callback {Function}
    • error {Error} Error object.
  • Returns {Socket} For chaining

Adds the client to the room, and fires optionally a callback with err signature (if any).

Example

io.on('connection', (socket) => {
  socket.join('room 237', () => {
    var rooms = Object.keys(socket.rooms);
    console.log(rooms); // [ <socket.id>, 'room 237' ]
    io.to('room 237').emit('a new user has joined the room'); // broadcast to everyone in the room
  });
});

The mechanics of joining rooms are handled by the Adapter that has been configured (see Server#adapter above), default: socket.io-adapter.

For your convenience, each socket automatically joins a room identified by its id (see Socket#id). This makes it easy to broadcast messages to other sockets:

io.on('connection', (socket) => {
  socket.on('say to someone', (id, msg) => {
    // send a private message to the socket with the given id
    socket.to(id).emit('my message', msg);
  });
});

socket.join(rooms[, callback])

  • rooms {Array}
  • callback {Function}
    • error {Error} Error object.
  • Returns {Socket} For chaining

Adds the client to the list of room, and fires optionally a callback with err signature (if any).

socket.leave(room[, callback])

  • room {String}
  • callback {Function}
    • error {Error} Error object.
  • Returns {Socket} For chaining

Removes the client from room, and fires optionally a callback with err signature (if any).

socket.to(room)

  • room {String}
  • Returns {Socket} For chaining

Sets a modifier for a subsequent event emission that the event will only be broadcasted to clients that have joined the given room (the socket itself being excluded).

To emit to multiple rooms, you can call to several times.

Example

io.on('connection', (socket) => {
  // to one room
  socket.to('others').emit('an event', { some: 'data' });
  // to multiple rooms
  socket.to('room1').to('room2').emit('hello');
  // a private message to another socket
  socket.to(/* another socket id */).emit('hey');
});

socket.in(room)

Synonym of socket.to(room).

socket.compress(value)

  • value {Boolean} Whether to following packet will be compressed
  • Returns {Socket} For chaining

Sets a modifier for a subsequent event emission that the event data will only be compressed if the value is true. Default: true when you don't call the method.

io.on('connection', (socket) => {
  socket.compress(false).emit('uncompressed', "that's rough");
});

socket.disconnect(close)

  • close {Boolean} Whether to close the underlying connection
  • Returns {Socket}

Disconnects this client. If value of close is true, closes the underlying connection. Otherwise, it just disconnects the namespace.

Example

io.on('connection', (socket) => {
  setTimeout(() => socket.disconnect(true), 5000);
});

Flag: 'broadcast'

Sets a modifier for a subsequent event emission that the event data will only be broadcast to every sockets but the sender.

io.on('connection', (socket) => {
  socket.broadcast.emit('an event', { some: 'data' }); // everyone gets it but the sender
});

Flag: 'volatile'

Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to receive messages (because of network slowness or other issues, or because they’re connected through long polling and is in the middle of a request-response cycle).

Example

io.on('connection', (socket) => {
  socket.volatile.emit('an event', { some: 'data' }); // the client may or may not receive it
});

Flag: 'binary'

Specifies whether there is binary data in the emitted data. Increases performance when specified. Can be true or false.

Example

var io = require('socket.io')();
io.on('connection', function(socket){
  socket.binary(false).emit('an event', { some: 'data' }); // The data to send has no binary data
});

Event: 'disconnect'

  • reason {String} The reason of the disconnection (either client or server-side)

Fired upon disconnection.

Example

io.on('connection', (socket) => {
  socket.on('disconnect', (reason) => {
    // ...
  });
});

Event: 'error'

  • error {Object} Error object

Fired when an error occurs.

Example

io.on('connection', (socket) => {
  socket.on('error', (error) => {
    // ...
  });
});

Event: 'disconnecting'

  • reason {String} The reason of the disconnection (either client or server-side)

Fired when the client is going to be disconnected (but hasn't left its rooms yet).

Example

io.on('connection', (socket) => {
  socket.on('disconnecting', (reason) => {
    var rooms = Object.keys(socket.rooms);
    // ...
  });
});

These are reserved events (along with connect, newListener and removeListener) which cannot be used as event names.

Client

The Client class represents an incoming transport (engine.io) connection. A Client can be associated with many multiplexed Sockets that belong to different Namespaces.

client.conn

  • {engine.Socket}

A reference to the underlying engine.io Socket connection.

client.request

  • {Request}

A getter proxy that returns the reference to the request that originated the engine.io connection. Useful for accessing request headers such as Cookie or User-Agent.

Example

  • client:
<!doctype html>
<html>

<head>
  <link rel="icon" href="data:image/ico;base64,aWNv">
  <script src="/socket.io/socket.io.js"></script>
  <title>Socket.IO chat</title>
</head>

<body>
  <div id='sysInfo'>...</div>
  <div name="d" style="width: 600px;height: 500px; margin-top: 10px; margin-left: 10px">
    <div>
      <input id="inputMsg" type="text" placeholder="new message" />
      <button onclick="onSend(document.getElementById('inputMsg').value)">Send</button>
    </div>
    </hr color="red">
    <textarea id="res" rows="10"></textarea>
  </div>

  <script>
    var sysInfo = document.getElementById('sysInfo');
    sysInfo.innerHTML = 'ready...<br/>';

    var socket = io();

    socket.on('connect', function () {
      sysInfo.innerHTML += socket.id + ' connect<br/>';
      socket.emit('req', 'req:', (data)=> {
        sysInfo.innerHTML += `${socket.id} res: ${data} <br/>`;
      });
    });

    socket.on('disconnect', function (timeout) {
      sysInfo.innerHTML += socket.id + ' disconnect<br/>';
    });

    socket.on('chat', function (msg) {
      var ta = document.getElementById('res');
      ta.value = msg.toString()  + '\r\n' + ta.value;
    });

    socket.on('hi', function (msg) {
      var ta = document.getElementById('res');
    ta.value = 'new client:' + msg.toString()  + '\r\n' + ta.value;
    });

    function onSend(msg) {
      socket.emit('chat', msg);
    }

  </script>
</body>
</html>
  • server:
var WebApp = require('webapp');
var socket = require('socket');
var iosched = require('iosched');
var Socket = require('socket.io');
var fs = require('fs');

function handleIndex(req, res) {
  var filePath = './index.html';
  var buf = fs.readFile(filePath);
  if (buf) {
    res.end(buf.toString());
  } else {
    return new Error('Read file error.');
  }
}

function handle(req, res) {
  res.end('This is socket.io test server.');
}

var app = WebApp.create('socketio', 0, socket.sockaddr(socket.INADDR_ANY, 8000));
app.get('/index.:ext', handleIndex);
app.all('/', handle);

var io = new Socket(app.server, { allowUpgrades: true });
io.on('connection', function (socket) {
  console.log(`client: ${socket.id} connected`);
  socket.broadcast.emit('hi', `I'm coming, my name: client_${socket.id}.`);

  socket.on('disconnect', function () {
    console.log(`client_${socket.id} disconnected`);
  });

  socket.on('req', function (msg, fn) {
    fn('hello world');
  });

  socket.on('chat', function (msg) {
    console.log(`recv chat message from: ${socket.id}`);
    io.emit('chat', `client_${socket.id} says: ${msg}`);
  });
});

app.start();

while (true) {
  iosched.poll(50);
}
文档内容是否对您有所帮助?
有帮助
没帮助