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:

  • a Node.js server: Source | API
  • a Javascript client library for the browser (which can be also run from Node.js): Source | API

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>

client-代码跟踪

https://github.com/socketio/socket.io-client

以客户端源码为研究对象。

在socket.js文件中,存在emit实现:

如下代码中, 17-20行代码中, 会将callback函数存储到本地的acks数组中, 并将基数记为 packet.id,

然后packet作为数据整体,传送的服务器端。

 Socket.prototype.emit = function (ev) {
if (events.hasOwnProperty(ev)) {
emit.apply(this, arguments);
return this;
} var args = toArray(arguments);
var packet = {
type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT,
data: args
}; packet.options = {};
packet.options.compress = !this.flags || false !== this.flags.compress; // event ack callback
if ('function' === typeof args[args.length - 1]) {
debug('emitting packet with ack id %d', this.ids);
this.acks[this.ids] = args.pop();
packet.id = this.ids++;
} if (this.connected) {
this.packet(packet);
} else {
this.sendBuffer.push(packet);
} this.flags = {}; return this;
};

服务器端处理完数据后, 调用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);
}
};

server-代码跟踪

https://github.com/socketio/socket.io

socket.js中 在onevent中 在数据的args数组之后, 添加了 acknowledge 回调函数

 /**
* Called upon event packet.
*
* @param {Object} packet object
* @api private
*/ Socket.prototype.onevent = function(packet){
var args = packet.data || [];
debug('emitting event %j', args); if (null != packet.id) {
debug('attaching ack callback to event');
args.push(this.ack(packet.id));
} this.dispatch(args);
}; /**
* Produces an ack callback to emit with an event.
*
* @param {Number} id packet id
* @api private
*/ Socket.prototype.ack = function(id){
var self = this;
var sent = false;
return function(){
// prevent double callbacks
if (sent) return;
var args = Array.prototype.slice.call(arguments);
debug('sending ack %j', args); self.packet({
id: id,
type: hasBin(args) ? parser.BINARY_ACK : parser.ACK,
data: args
}); sent = true;
};
};

在 dispatch 负责调用 emitter 原生接口 on 绑定的 事件处理函数:

/**
 * `EventEmitter#emit` reference.
 */

var emit = Emitter.prototype.emit;

/**
* Dispatch incoming event to socket listeners.
*
* @param {Array} event that will get emitted
* @api private
*/ Socket.prototype.dispatch = function(event){
debug('dispatching an event %j', event);
var self = this;
function dispatchSocket(err) {
process.nextTick(function(){
if (err) {
return self.error(err.data || err.message);
}
emit.apply(self, event);
});
}
this.run(event, dispatchSocket);
}; /**
* Sets up socket middleware.
*
* @param {Function} middleware function (event, next)
* @return {Socket} self
* @api public
*/ Socket.prototype.use = function(fn){
this.fns.push(fn);
return this;
}; /**
* Executes the middleware for an incoming event.
*
* @param {Array} event that will get emitted
* @param {Function} last fn call in the middleware
* @api private
*/
Socket.prototype.run = function(event, fn){
var fns = this.fns.slice(0);
if (!fns.length) return fn(null); function run(i){
fns[i](event, function(err){
// upon error, short-circuit
if (err) return fn(err); // if no middleware left, summon callback
if (!fns[i + 1]) return fn(null); // go on to next
run(i + 1);
});
} run(0);
};

至此实现上彻底明了了。

socket.io emit callback调用探秘的更多相关文章

  1. socket.io emit 常见用法

    io.on('connect', onConnect); function onConnect(socket){ // 只发给sender. sending to the client socket. ...

  2. 使用 Socket.IO 开发聊天室

    前言 Socket.IO 是一个用来实现实时双向通信的框架,其本质是基于 WebSocket 技术. 我们首先来聊聊 WebSocket 技术,先设想这么一个场景: · 用户小A,打开了某个网站的充值 ...

  3. 关于Socket.IO的知识点记录

    最近因为项目的需要,开始学习nodejs,本着js的那点儿功底,nodejs学习起来还是挺快能上手的.随着深入学习,知道了express框架并那它写了一个小功能,作为一个php程序员哈,在expres ...

  4. AngularJS+Node.js+socket.io 开发在线聊天室

    所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...

  5. node基于express的socket.io

    前一段事件,我一个同学给他们公司用融云搭建了一套web及时通信系统,然后之前我的公司也用过环云来实现web及时通信,本人对web及时通信还是非常感兴趣的.私下读了融云和环信的开发文档,然后发现如果注册 ...

  6. socket.io的基本使用

    服务端: 1.监听客户端连接: io.on("connection",socket=>{ }); 不分组数据传输:传输对象为当前socket 2.1给该socket所有客户端 ...

  7. 利用socket.io实现消息实时推送

    最近在写的项目中存在着社交模块,需要实现这样的一个功能:当发生了用户被点赞.评论.关注等操作时,需要由服务器向用户实时地推送一条消息.最终完成的项目地址为:socket-message-push,这里 ...

  8. Socket.IO基础教程

    什么是Socket.IO Socket.IO是一个库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信.它包括: 使Node.js服务器:来源 | API 为浏览器(可从Node.js的也运行 ...

  9. 【socket.io研究】1.官网的一些相关说明,概述

    socket.io是什么? 官网的解释是一个实时的,基于事件的通讯框架,可以再各个平台上运行,关注于效率和速度. 在javascript,ios,android,java中都实现了,可以很好的实现实时 ...

随机推荐

  1. k8s 集群部署问题整理

    1.hostname “master” could not be reached在host中没有加解析 2.curl -sSL http://localhost:10248/healthzcurl: ...

  2. Troubleshooting 'library cache: mutex X' Waits. (Doc ID 1357946.1)

    In this Document   Purpose   Troubleshooting Steps   What is a 'library cache: mutex X' wait?   What ...

  3. dump解析入门-用VS解析dump文件进行排障

    突然有一天部署在服务器的一个应用挂掉了,没办法只能进入服务器打开 [事件查看器]查看下,好不容易找到了打开后一脸懵逼 事件查看器查到的内容根本对我们排障没有任何作用. 在这个时候如果有对应的dump文 ...

  4. Socket网络编程(案例)

    Socket:套接字 java.net包 1.流式套接字:基于TCP协议的Socket网络编程 工作方式: 1.客户端A连接到服务器: 2.服务器建立连接并把客户端A添加到列表: 3.客户端B.C.. ...

  5. 论学好Linux系统的超级重要性

    不知道各位在日常的工作生活中有没有接触过“rm -rf /*”这个命令,因为这个命令搞出来的事情可还不少呢!前段时间就在一个群里看到了有个小伙子,老板让他去维护一下服务器,这小伙也不太懂,就问群里的大 ...

  6. 什么是CAS机制?(转)

    围绕下面四个点展开叙述: 一:什么是CAS机制? 二:Java当中CAS的底层实现 三:CAS的ABA问题和解决方法 四:java8对CAS的优化 一:什么是CAS机制? 我们先看一段代码: 启动两个 ...

  7. ftm国际化解决方案

    记录一下踩过的坑,在使用ftm:message的时候我发现这个的国际化是依赖于本地浏览器的语言环境的!关于自主设置这个语言的方法有如下3种:(个人建议使用第二种,可以更加灵活且有效!第一种我这边没有生 ...

  8. “纽劢科技杯”第十六届同济大学程序设计竞赛暨上海邀请赛同步赛 J-张老师的游戏

    传送门 题目描述     在空闲时间,张老师习惯性地和菜哭武玩起了取石子游戏,这次的游戏规则有些不同,在他们面前有n堆石子,其中,第i堆石子的个数为a[i],现在制定规则如下:     从张老师开始, ...

  9. 第一章 Python基本语法元素

    1.1   程序设计基本方法 计算机的概念: (1)功能性:对数据的操作,表现为数据计算.输出输出处理和结果存储等 (2)可编程性:根据一系列指令自动地.可预测地.准确地完成操作者的意图. 计算机的发 ...

  10. js的数组的一些操作

    1 arr.reduce let xxx = arr.reduce( function (pv, cv, ci ,arr) { return }[, init_val] ) 对arr的每个元素,执行匿 ...