这篇主要分析ws的客户端。时序图在页末,不想看代码的直接翻到底部就可以了
var WebSocket = require('ws');
var ws = new WebSocket('ws://127.0.0.1:19999');
ws.on('open', function open() {
ws.send(...);
});
ws.on('message', function message(data, flags) {
...
});
上面是文档给的示例, 所以这次研究的是 open\color{green}{open}open, message\color{green}{message}message 事件何时被调用。
var WS = module.exports = require('./lib/WebSocket');
function WebSocket(address, protocols, options) {
initAsClient.apply(this, [address, protocols, options]);
}
function initAsClient(address, protocols, options) {
....省略 requestOptions 初始化部分
var req = httpObj.request(requestOptions);
req.once('response', function response(res) {
// 关闭连接
cleanupWebsocketResources.call(self, error);
});
req.once('upgrade', function upgrade(res, socket, upgradeHead) {
...
establishConnection.call(self, Receiver, Sender, socket, upgradeHead);
});
req.end();
}
function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) {
var ultron = this._ultron = new Ultron(socket), called = false, self = this;
// 连接永不超时
socket.setTimeout(0);
this._receiver = new ReceiverClass(this.extensions,this.maxPayload);
this._socket = socket;
function firstHandler(data) {
socket.removeListener('data', firstHandler);
ultron.on('data', realHandler);
if (data) realHandler(data);
}
function realHandler(data) {
self._receiver.add(data);
}
ultron.on('data', firstHandler);
process.nextTick(firstHandler);
self._receiver.ontext = function ontext(data, flags) {
self.emit('message', data, flags);};
self._receiver.onbinary = function onbinary(data, flags) {
self.emit('message', data, flags);};
this._sender = new SenderClass(socket, this.extensions);
this.emit('open');
}
上述代码, open\color{green}{open}open 事件 由 upgrade\color{green}{upgrade}upgrade 事件 触发。 message\color{green}{message}message 事件 没有看到触发代码, 但是相关代码有 self._receiver.ontext。 同时又暴露了几个问题:
- response\color{green}{response}response 事件 一旦被触发, 说明连接会被强制关闭。 那什么情况会被触发这个事件
- upgrade\color{green}{upgrade}upgrade 事件 何时会触发
- ultron 的 data\color{green}{data}data 事件 何时触发
提供一个debug命令,这样就可以打印一些内部的注释信息, 帮助阅读源码
export NODE_DEBUG=*
这个是 requestOptions
{ port: ‘19999’,
host: ‘127.0.0.1’,
headers:
{ Connection: ‘Upgrade’,
Upgrade: ‘websocket’,
Host: ‘127.0.0.1:19999’,
‘Sec-WebSocket-Version’: 13,
‘Sec-WebSocket-Key’: ‘MTMtMTU2NDQ5MDMxMDY1OQ==’,
‘Sec-WebSocket-Extensions’: ‘permessage-deflate; client_max_window_bits’ },
path: ‘/’ }
// 源码包路径/lib/http.js
function request(url, options, cb) {
return new ClientRequest(url, options, cb);
}
// 源码包路径/lib/_http_client.js
function ClientRequest(input, options, cb) {
OutgoingMessage.call(this);
var agent = options.agent;
var defaultAgent = options._defaultAgent || Agent.globalAgent;
agent = defaultAgent;
this.agent = agent;
this.agent.addRequest(this, options);
this._deferToConnect(null, null, () =>