每天看一片代码系列(二):WebSocket-Node
简介
我们都知道,websocket主要是通过在浏览器和服务端建立长连接,继而实现二者的相互数据通信。不同于HTTP的轮询,它不会有大量无效的HTTP消息交换,从而节省了花销。websocket其实就是双通道的TCP连接。
很明显地,整个工作分为两个步骤,即创建连接和发送数据。那么连接是怎么建立的呢?其实只需要在浏览器和服务器端做一个握手的动作就可以了。而这个握手其实还是一个HTTP请求,只是接下来的工作就和HTTP没关系了。
这个HandShake的请求消息大致为:
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
而响应的消息大致为:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
HTTP里面的upgrade头部代表要从HTTP协议切换到另一个协议,或者是更换一个不同版本的HTTP。而Sec-WebSocket-Key和Sec-WebSocket-Accept是用来进行验证的字段。后者是前者经过一系列操作计算出来的,用来给客户端判断响应和请求是否匹配。
使用WebSocket-Node
首先我们体验一下“websocket-node"这个库的用法。
其实用这个库就是为了创建一个websocket-server,在app.js中,我们创建即可。
var port = 3001;
var websocketServer = require('websocket').server;
var http = require('http'); // 创建httpServer
var httpServer = http.createServer();
httpServer.listen(port, function () {
console.log(new Date() + " Http Server is listening on " + port);
}); //创建WebSocketServer
var wsServer = new websocketServer({
httpServer: httpServer
}); wsServer.on('request', function (request) {
console.log(new Date() + " connection from origin: " + request.origin + ' .');
//建立连接
var connection = request.accept('example', request.origin); //向客户端发送消息
connection.sendUTF("Connection from " + request.origin); connection.on('close', function () {
console.log(connection.remoteAddress + " disconnected.");
}) //收消息
connection.on('message', function (message) {
try{
connection.sendUTF("Server accpected: " + message.utf8Data);
}catch(e){ }
})
})
在浏览器中,就和这个库没什么关系了,直接用浏览器支持的API创建Websocket客户端,收发消息即可。
var wsServer = "ws://localhost:3001";
var ws = new WebSocket(wsServer, 'example'); ws.onopen = function (e) {
var msg = "hello Server!";
ws.send(msg) && print(msg);
} ws.onclose = function (e) {
var msg = "closed connection";
print(msg);
} ws.onmessage = function (e) {
var msg = "received : " + e.data;
print(msg);
}
源码解析
源码有多个文件,我们只关注WebSocketServer.js,地址
首先,在传入的配置中必须要绑定一个httpServer用于握手。当客户端建立连接时,首先会进行握手,会触发server的upgrade事件,从而进入到服务端的处理函数中去。在这个函数中,会创建一个wsRequest对象,并将它作为request事件的参数发送出去。接下来根据客户端的Accept情况来进入到handleRequestAccepted,接下来connect事件会被触发。
var upgradeHandler = this._handlers.upgrade;
this.config.httpServer.forEach(function(httpServer) {
httpServer.on('upgrade', upgradeHandler);
}); handleUpgrade:
var wsRequest = new WebSocketRequest(socket, request, this.config);
try {
wsRequest.readHandshake();
}
wsRequest.once('requestAccepted', this._handlers.requestAccepted);
wsRequest.once('requestResolved', this._handlers.requestResolved);
if (!this.config.autoAcceptConnections && utils.eventEmitterListenerCount(this, 'request') > 0) {
this.emit('request', wsRequest);
} handleRequestAccepted:
this.connections.push(connection);
this.emit('connect', connection);
另外,WebsocketServer继承了EventEmitter,所以具有事件处理的能力:
util.inherits(WebSocketServer, EventEmitter);
每天看一片代码系列(二):WebSocket-Node的更多相关文章
- 每天看一片代码系列(一):stream.js
简介 stream.js是一个小型的js库,用于处理stream相关的操作.这里的stream是指一种数据结构,它像数组一样,可以放置多个类型的数据,但是并不限制长度,甚至可以达到无限长.可以对该数据 ...
- 少侠学代码系列(二)->JS实现
少侠:小子,休息好了没,赶紧的 帅气的我:好了好了,嚷什么 少侠:(拔刀)嗯? 帅气的我:少侠,淡定淡定,我们来看秘籍吧,刚刚我们说了JS实现是由三个部分组成的 核心(ECMAScript),文档对象 ...
- 每天看一片代码系列(四):layzr.js,处理图片懒加载的库
所谓图片的懒加载,即只有当图片处于或者接近于当前视窗时才开始加载图片.该库的使用方法非常简单: var layzr = new Layzr({ attr: 'data-layzr', // attr和 ...
- 每天看一片代码系列(三):codepen上一个音乐播放器的实现
今天我们看的是一个使用纯HTML+CSS+JS实现音乐播放器的例子,效果还是很赞的: codePen地址 HTML部分 首先我们要思考一下,一个播放器主要包含哪些元素.首先要有播放的进度信息,还有播放 ...
- RabbitMQ学习系列二-C#代码发送消息
RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...
- SonarQube系列二、分析dotnet core/C#代码
[前言] 本系列主要讲述sonarqube的安装部署以及如何集成jenkins自动化分析.netcore项目.目录如下: SonarQube系列一.Linux安装与部署 SonarQube系列二.分析 ...
- 图机器学习(GML)&图神经网络(GNN)原理和代码实现(前置学习系列二)
项目链接:https://aistudio.baidu.com/aistudio/projectdetail/4990947?contributionType=1 欢迎fork欢迎三连!文章篇幅有限, ...
- swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?
date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowf ...
- Web 开发人员和设计师必读文章推荐【系列二十九】
<Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...
随机推荐
- 在一个Excel单元格内输入多行内容
有时候,我们想在一个Excel单元格中输入多行内容,可以根据不同情况选择下面的方法来实现: 方法一:如果有大量的单元格需要这样做,采取此种设置格式的方法,选中需要这种格式的单元格,执行“格式→单元格” ...
- ListView实现分页加载(三)实现分页加载
在上一篇中,我们实现了底部布局(即带上了进度条).没有读过的朋友可以点击下面的链接: http://www.cnblogs.com/fuly550871915/p/4866966.html 但是进度条 ...
- CF1063A Oh Those Palindromes
嘟嘟嘟 只要将每一种字母放一块输出就行了. 证明1:比如 1 2 3 4 5 6,那么这个序列对答案的贡献分别是1和5,2和4 ,3和6……如果重新排列成x x x x o o,会发现对 ...
- PHP----练习-----三级联动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 总结PHP删除字符串最后一个字符的三种方法
一.前言 从数据库中select()读取一对多的信息时,经常需要将取出的数组用某个特定的字符分割,然后拼接成字符串. 常见的语法格式: foreach ($arr as $key => $val ...
- form表单上传文件
一.formData()直接获取form表单数据 例子:获取form表单的id给formData(),然后传给后台. 要求: 传入值的name值必须与后台接受的name相对应. form表单不能嵌套, ...
- git上传下载代码操作
提交代码实质上都要走这样的操作 " 本地代码 --> 本地服务器" "本地服务器 --> 远程服务器" 其实小伙伴就记住两个词就好了. Commi ...
- GIT 报错:Result too large 解决办法
在使用bower install命令下载前端依赖的js插件时,git出错了,报错信息如下: bower ECMDERR Failed to execute "git ls-remote -- ...
- css百分比问题——`top`、`left`、'translate'的百分比参照谁?
比如 top.left.transform属性的translate方法,他们的百分比都是相较谁而言的? top.left是基于父元素的: .parent { position: relative; b ...
- 随机数使用不当引发的生产bug
前几天负责的理财产品线上出现问题:一客户赎回失败,查询交易记录时显示某条交易记录为其他人的卡号. 交易的链路如下: 出现该问题后,我们对日志进行了分析,发现主站收到的两笔流水号完全相同,然而主站却没有 ...