WebSocket系列之socket.io
导语:上篇讲了WebSocket基础知识和浏览器端的实现,WebSocket server和http server也是有区别的,这篇开始讲nodejs平台的一个很成熟,知名度也最大的WebSocket实现--socket.io
socket.io:
1.跨浏览器、跨平台,多种连接方式自动切换
2.功能完善,心跳检测,断线自动重连
3.server和client必须配套使用,不能直接用原生WebSocket
socket.io server:
socket.io client:
参数说明:
1.client必须引用socket.io的client js文件,没法用原生WebSocket
2.server端的path和client端的path必须对应上,并且server端设置的path也是client引用的js的path
3.server端的serveClient控制socket.io client js是否可以被引用,默认true,如果设为false,那么client里会加载不到socket.io client js文件
4.client端的transports设置的是websocket连接的建立方式,默认值是'polling', 'websocket',可以设置成'websocket',区别是使用默认的会先用http拉取session id,再升级到WebSocket,如果设置成'websocket'会跳过http请求,直接用WebSocket建立连接,如下图:
'polling', 'websocket':
'websocket':
断线重连:
socket.io已经帮我们实现了断线重连,当server close的时候,client会马上探测到并开始尝试重连,如下图
多进程和分布式部署:
看了上面的说明,是不是觉得socket.io真简单,分分钟掌握,开始撸代码,却不知等到你的产品用户量上来的那一天,并发上不去了,你开始得心应手的用cluster开启多进程,还不够,再分部署部署,实现代码如下:
特别说明:你在windows版nodejs测试上面代码时,你会发现每次请求都到同一个worker,看着socket.io多进程正常运行,不过布到linux里就会出现请求400,那是因为windows版nodejs的负载均衡算法和linux不一样(负载均衡算法),linux用的Round-Robin(轮询调度),window版因为Round-Robin有性能问题,暂时用的操作系统的算法,不过文档说等到性能问题解决了,会切到Round-Robin,我们也可以如上面代码第三行,通过设置cluster.schedulingPolicy = 2;为windows开启Round-Robin,一旦开启,就会出现请求400,如下图:
出现400原因是:拉取session id的进程和用该session id建立连接的进程不是同一个,甚至不是同一台服务器,进程A给你分配的session id,进程B当然不认识,也就不会给你建立socket连接了,我们需要保证一个用户的多次连接由同一个进程处理,不仅是session id,也是因为不支持WebSocket的浏览器,socket.io会降级使用轮询实现socket,而这种socket是由多次请求组成的,如果两次请求不是同一个进程处理,运行时都不一致,会出现各种问题
解决方案:上面已经说了,就是保证一个用户的多次连接由同一个进程处理,具体怎么做了,就是nginx代理,原理是nginx支持根据client ip分发请求到对应进程
nginx可以把请求直接分发到nodejs的worker进程,这种就需要同一台机器的各worker进程监听私有端口,并且在nginx配置那里配置对应port,或者由master进程监听一个端口,nginx分发请求到master,再由master分配到worker,这就是socket.io里的sticky session,下面说明
sticky session(实现代码如下图):
说明:
1.根据cpu数开启多进程
2.master监听一个port,启动net server,参数pauseOnConnect:true必须有,因为master接收connect,是为了再分发到worker,master不需要读取数据,数据读取应该由worker来完成
3.根据remoteAddress决定分发给哪个worker,这样就能保证同一个remoteAddress必然由同一个worker处理
至此sticky session实现完成,完美根据client ip分发请求,再也不会请求400了
demo代码都放在附件了,各位可以本地运行试下,当然本地需要安装nodejs和socket.io了
附件:
- 优化算法——粒子群算法(PSO)
- Java开发画板
- Python—numpy模块下函数介绍(一)numpy.ones、empty等
- Tomcat用户权限设置
- 优化算法——模拟退火算法
- 绘制动态心形图案::R语言绘制心形图
- 物化视图中的统计信息导致的查询问题分析和修复 (r7笔记第47天)
- R语言之系统聚类(层次)分析之图谱形式完整版
- Java操作数据库Spring(1)
- python基础知识——内置数据结构(集合)
- 关于db link权限分配的苦旅(二)(r7笔记第45天)
- 简单易学的机器学习算法——在线顺序极限学习机OS-ELM
- Java操作数据库Spring(2)
- 解决SSH连接linux中文显示乱码问题
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python实现信息自动配对爬虫排版程序
- EOF是不是字符
- Alibaba开源Java诊断工具Arthas简单介绍
- 气象编程 | Google Earth Engine for R——提供250+ 实例
- Anaconda安装和使用
- Redhat7安装docker
- 有个笔记本就可以玩一玩Hadoop
- java如何将String转换为Int
- java中如何将数组转换为List
- 从一个多层嵌套循环中直接跳出
- 如何给3个布尔变量,当其中有2个或者2个以上为true才返回true
- 比较java枚举成员使用equal还是==
- java如何将String转换为enum
- Markdown极简入门教程(1)—为什么要学习Markdown
- Markdown极简入门教程(2)—斜体和粗体