A. WebSocket 的实现
长连接: 一个链接上可以连续发送多个数据包,在链接期间,如果没有数据包发送,需要双方发链路检查包
TCP/IP: TCP/IP 属于传输层,主要解决网络中的数据传输问题,只管传输数据。但这样对传输的数据没有一个规范的封装、解析等处理。使得传输的数据难前咐以识别,所以才有了应用层协议对数据进行的封装、解析等,如http协议。
HTTP: HTTP协议是慧虚纯应用层协议,用于分装解析传输数据。 从HTTP1.1开始其实就默认开启了长链接,也就是请求头header中可以看到Connection:Keep-alive。但是长连接只是说保持了(服务器可以告诉客户端保持时间Keep-Alive:timeout=20;max=20;)这个TCP通道,并采用服务器和客户端应答模式(Request-Response),不需要再创建一个链接通道,做到一个性能优化。
socket: 与HTTP协议不一样,socket不是协议,他是在程序层面上对传输层协议(像TCP/IP)的接口封装。我们知道传输层的协议,是解决数据在网络中传输的问题的,那么socket(套接字)就是传输通道两端的接口。
Websocket: WebSocket是包装成了一个应用层协议作为socket,从而能够让客户端和远程服务端通过web建立全双工通信。
WebSocket API 是HTML5 推出的东誉闷西。在客户端我们可以通过HTML5 所提供的API 对websocket 进行创建、发送数据、监听信息、监听报错等功能( HTML5 WebSocket )
我们知道WebSocket 是在Socket的基础上实现的,所以我们要做的是对现有的Socket协议进行升级。
步骤: 客户端发送websocket请求-->服务端接受并识别该请求-->对该请求协议进行升级--> 返回给客户端 --> websocket 通道建立 --> 客户端/服务端发送数据
协议升级
在这里需要注意的是头部信息和头部信息中的Sec-Websocket-Accept的值。
该值需要是一个通过base64加密的哈希值(sha1)。 而该加密所用的数据是客户端传过来的sec-websocket-key的值和MAGIC_STRINC内的固定值。 对MAGIC_STRINC的说明
Webscoket 中传输的数据是 数据帧(frame)
数据帧有多种类型 主要有:文本型、二进制数据
数据帧结构
每一列代表一个字节,一个字节8位,每一位又代表一个二进制数。
创建数据帧
解数据帧
心跳检查
由于websocket 不进行交互会关闭通道所以,才有了心跳检查。
websocket与和他http的区别
基于node实现websocket协议
使用nodejs在HTTP上实现WebSocket
如何让我的服务器返回正确的Sec-WebSocket-Accept标头值
学习WebSocket协议—从顶层到底层的实现原理
websocket 协议帧 解析
nodejs实现Websocket的数据接收发送
B. nodejshttp不走系统代理
现在使用的代理大部分为HTTP和Socket代理。 Socket代理更底层,需要本地解析域名,而HTTP代理则是基于HTTP协议之上的,不需要本地解析域名。下面我讲讲HTTP(S)代理的设计思路以及NodeJS代码实现。
<br/>
<br/><strong>HTTP协议</strong>
<br/>
<br/>HTTP协议简单说来就是浏览器把一串字符串发送到目标服务器,然后把目标服务器返回回来的一串字符串显示给用户。
<br/>
<br/>浏览器发送链银岩的这串字符主要分为两个部分,一部分是头,里面包含目标服务器域名,当前请求的文件路径等信息。另一部分是正文,一般的GET请求没有正文。
<br/>
<br/>服务器返回来的字符串也分为头和正文。
<br/>
<br/><strong>HTTP代理原理</strong>
<br/>
<br/>HTTP代理需要做的事情就是接收浏览器发来的请求字符串,再从请求字符串的头部分找出浏览器请求的目标主机,然后直接把这串请求字符串发给目标主机,再把目标主机返回的数据发给浏览器。 “什么?就这么简单?” “呃。。是啊,但这还没完。。”
<br/>
<br/>现代浏览器一般都是默认采用HTTP/1.1版本,并且默认会发送Connection: keep-alive请求。 这些信息是写在请求的头部的,意思是通知目标服务器采用keep-alive技术继续处理后续的请求。 但是我们做的代理程序要想支持keep-alive是比较麻烦的。所以干脆就把这个篡改成Connection: close。 这样就可以保证浏览器请求的每个文件都会单独发送一个HTTP请求。
<br/>
<br/><strong>下面是NodeJS代码实现</strong>
<br/><pre escaped=“true” lang=“javascript”>var net = require(‘net’);
<br/>var local_port = 8893;
<br/>
<br/>//在本地创建一个server监听本地local_port端口
<br/>net.createServer(function (client)
<br/>{
<br/>
<br/> //首先监听浏览器的数据发送事件,直到收到的数据包含完整的http请求头
<br/> var buffer = new Buffer(0);
<br/> client.on(‘data’,function(data)
<br/> {
<br/> buffer = buffer_add(buffer,data);
<br/> if (buffer_find_body(buffer) == -1) return;
<br/> var req = parse_request(buffer);
<br/> if (req === false) return;
<br/> client.removeAllListeners(‘data’);
<br/> relay_connection(req);
<br/> });
<br/>
<br/> //从http请求头部取得请求信息后,继续监听浏览器发送数据,同时连接目标服务器,并把目标服务器的数据传给浏览器代理的出现是因为浏览器同源策略的存在
服务端实现代理的例子和方法很多 比如nginx 反向代理解决生产环境的跨域问题
再有http-server等一些第三方的包帮我处理 基本达到了开箱即用的体验
通常我们所说的代理来源于http1.1的定义,代理扮演的是「中间人」角色,对于连接到它的客户端来说,它是服务端;对于要连接的服务端来说,它是棚御客户端。它就负责在两端之间来回传送 HTTP 报文
假如我通过代理访问A网站,对于A来说,它会把代理当做客户端,完全察觉不到真正客户端的存在,这实现了隐藏客户端IP的目的。
但是他们到底是如何实现的 ,值得一探究竟,下面是用原生nodejs 写个以后个代理
const http = require("http");
const url = require("url");
//首先启动本地服务器
http.createServer(function(req, res) {
//客户端请求有两种方式,可以是对象,也可以是url字符串
//1.这里采取的是对象形式,包括url对象以及headers
var options = url.parse(req.url);
options.headers = req.headers;
//2.如果采取字符串形式,就传入一个完整的url字符串,node会自动解析成url对象
//通过客户端请求新建一个代理服搏高务器
//代理请求仿照本地请求头的数据
var proxyRequest = http.request(options, function(proxyResponse) { //代理请求获取的数据再返回给本地res
proxyResponse.on('data', function(chunk) {
console.log('proxyResponse length:', chunk.length);
res.write(chunk, 'binary');
});
//当代理请求不再收到新的数据,告知本地res数据写入完毕。
proxyResponse.on('end', function() {
console.log('proxied request ended');
res.end();
});
res.writeHead(proxyResponse.statusCode, proxyResponse.headers);
});
//data只有当请求体数据进来时才会触发
//尽管没有请求体数据进来,data还是要写,否则不会触发end事件
req.on('data', function(chunk) {
console.log('in request length:', chunk.length);
proxyRequest.write(chunk, 'binary');
});
req.on('end', function() {
//向proxy发送求情,这里end方法必须被调用才能发起代理请求
//所有的客户端请求都需要通过end来发起
proxyRequest.end();
});
}).listen(8080);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
以上代码的核心思想就是用http.request充当了中间人的角色 帮我们去目标地址取数据然后在把得到的数据传回去。可以看作是设计模式中代理模式的一种实践
C. 如何用websocket+nodejs实现web即时通信服务端
用websocket+nodejs实现web即时通信服务端,Socketio和nodejs配的不错,建立了socket就可以listen和broadcast。
D. node.js适合做什么网站
NodeJS的特点:
它是一个Javascript运行环境
依赖于Chrome V8引擎进行代码解释
事件驱动
非阻塞I/O
轻量、可伸缩,适于实时数据交互应用
单进程,单线程
NodeJS的缺点:
1. 不适合CPU密集型应用;CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;
2. 只支持单核CPU,不能充分利用CPU
3. 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃
原因:单进程,单线程
解决方案:
(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;
(2)开多个进程监听同一个端口,使用cluster模块;
4. 开源组件库质量参差不齐,更新快,向下不兼容
5. Debug不方便,错误没有stack trace
NodeJS的应用场景:
实时应用:如在线聊天,实时通知推送等等(如socket.io)
分布式应用:通过高效的并行I/O使用已有的数据
工具类应用:海量的工具,小到前端压缩部署(如grunt),大到桌面图形界面应用程序
游戏类应用:游戏领域对实时和并发有很高的要求(如网易的pomelo框架)
NodeJS不适合场景:
CPU使用率较重、IO使用率较轻的应用——如视频编码、人工智能等,Node.js的优势无法发挥简单Web应用——此类应用的特点是,流量低、物理架构简单,Node.js无法提供像Ruby的Rails或者Python的Django这样强大的框架