socket.io
https://socket.io/
https://socket.io/docs/
What Socket.IO is
Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server. It consists of:
emit callback 用法
https://stackoverflow.com/questions/20337832/is-socket-io-emit-callback-appropriate
Recently I have been messing around with socket.io and found this interesting thing, that I can have emit function callback like this.
I start emitting on client side like this:
client.emit(‘eventToEmit‘, dataToEmit, function(error, message){ console.log(error); console.log(message); });
Then I can fire a callback from server-side like this:
client.on(‘eventToEmit‘, function(data, callback){ console.log(data); callback(‘error‘, ‘message‘); });
Everything works fine with no errors, but I am interested if doing something like this is appropriate since I have not seen anything similar in the documentation or any example so far.
见老外的疑惑,也是本篇的主题, 为什么服务器端能够直接调用客户端设置的回调函数。
跨进程可以调用函数,真是稀奇。 类似RPC。
官方文档的解释
https://socket.io/docs/#Sending-and-getting-data-acknowledgements
Sending and getting data (acknowledgements)
Sometimes, you might want to get a callback when the client confirmed the message reception.
To do this, simply pass a function as the last parameter of
.send
or.emit
. What’s more, when you use.emit
, the acknowledgement is done by you, which means you can also pass data along:Server (app.js)
var io = require(‘socket.io‘)(80); io.on(‘connection‘, function (socket) { socket.on(‘ferret‘, function (name, word, fn) { fn(name + ‘ says ‘ + word); });});Client (index.html)
<script> var socket = io(); // TIP: io() with no args does auto-discovery socket.on(‘connect‘, function () { // TIP: you can avoid listening on `connect` and listen on events directly too! socket.emit(‘ferret‘, ‘tobi‘, ‘woot‘, function (data) { // args are sent in order to acknowledgement function console.log(data); // data will be ‘tobi says woot‘ }); });</script>
代码跟踪
https://github.com/socketio/socket.io-client
以客户端源码为研究对象。
在socket.js文件中,存在emit实现:
如下代码中, 17-20行代码中, 会将callback函数存储到本地的acks数组中, 并将基数记为 packet.id,
然后packet作为数据整体,传送的服务器端。
1 Socket.prototype.emit = function (ev) { 2 if (events.hasOwnProperty(ev)) { 3 emit.apply(this, arguments); 4 return this; 5 } 6 7 var args = toArray(arguments); 8 var packet = { 9 type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT, 10 data: args 11 }; 12 13 packet.options = {}; 14 packet.options.compress = !this.flags || false !== this.flags.compress; 15 16 // event ack callback 17 if (‘function‘ === typeof args[args.length - 1]) { 18 debug(‘emitting packet with ack id %d‘, this.ids); 19 this.acks[this.ids] = args.pop(); 20 packet.id = this.ids++; 21 } 22 23 if (this.connected) { 24 this.packet(packet); 25 } else { 26 this.sendBuffer.push(packet); 27 } 28 29 this.flags = {}; 30 31 return this; 32 };
服务器端处理完数据后, 调用callback接口后,服务器端调用的接口为包装接口, 包装了数据为packet, 并将id打在packet上, 表示此packet为emit时候的packet对应。
服务器端数据到来后, 根据packet.id定位到 callback函数, 并将packet.data作为参数传递到callback中。
/** * Called upon a server acknowlegement. * * @param {Object} packet * @api private */ Socket.prototype.onack = function (packet) { var ack = this.acks[packet.id]; if (‘function‘ === typeof ack) { debug(‘calling ack %s with %j‘, packet.id, packet.data); ack.apply(this, packet.data); delete this.acks[packet.id]; } else { debug(‘bad ack %s‘, packet.id); } };
致此实现上彻底明了了。
原文地址:https://www.cnblogs.com/lightsong/p/10226940.html