`
yiminghe
  • 浏览: 1431549 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

socket in js

阅读更多

socket 如今也出现在了 javascript 中,浏览器端有 html5 规范的 websocket 来完成客户端信息发送,服务器端则可以在 nodejs 平台上实现对应的服务器信息接收 (原生支持的异步io读取),而另一方面客户端 api 由 w3c 制定,具体的通信协议则由 IETF 指定,目前尚处于草稿阶段,最新的规范也已过期。

 

 

客户端发送:

 

目前只有 chrome 支持 websocket ,通过

 

var webSocket = new WebSocket('ws://xx.com:8081/');

 

 来创建客户端 socket 对象,而具体通信协议则是采用更早的 draft-ietf-hybi-thewebsocketprotocol-00

 

通过 send 方法来发送 utf-8 编码的文本信息(二进制上尚不支持)。通过 onopen , onmessage 回调来获取服务器端的对应返回状态和数据。

 

基本原理:

 

首先是握手阶段(handshake):浏览器发送 http get 请求到对应 xx.com:8081 ,并携带对应协议头 :

 

 

 

注意最后的 (key3) 并不表示一个 http header,而是在头结束后第二行的8个字节为 0x7D 0x24 ....,这8字节不属于 header 部分,由于是 get 请求,也不属于 body部分,造成一般的 web 容器经过层层封装后应用根本读不出来。

 

服务器端然后设置返回状态码 101 ,并根据 sec-websocket-key1/2 以及最后的 8 个字节,计算出另外一个字符串回来确认(challenge response 为了安全?):

 

 

 

 

至此,握手完毕,该 http 链接的 tcp 链接保留,以后数据传输直接通过 socket 进行(也即提升为 websocket),不过数据开头以 0x00 开头,以 0xFF 结尾,服务器端也是如此,只不过浏览器端会自动进行数据解包,因而对应用透明。

 

 

服务器端接收:

 

 

服务器实际上是一个特殊的 web (http)服务器,不同于一般的 http server,应用完全不需要了解 http 底层的 tcp socket,在 websocket 请求时就要适当暴漏承载 http 链接的 tcp socket,所以目前的 servlet 容器例如 tomcat就不行了(不可能从 httpRequest 直接得到它关联的 socket,被 tomcat 屏蔽了,另一个原因是不能读到请求的 raw data 造成 key3 读不到),这才有了 jetty 经过改造后支持 websocket 的 servlet 容器,或者直接手写 websocket 专用服务器

 

nodejs 下实现

 

nodejs 的 http server 已经支持 websocket 的握手阶段,能够将握手阶段作为事件触发出来,并且读出 key3,一旦到了握手阶段,该 socket 就会暴露出来 :

 

 server.on('upgrade', function(req, socket, upgradeHead) {    });

 

这时应用就可以设置 socket 为 keepalive 一直保持打开状态:

 

socket.setKeepAlive(true, 0);

 

接下来就是读取对应的 key1 和 key2 以及 key3,计算需要返回的确认值,以及准备其他必要的信息头(origin,location...)发送到客户端

 

res = 'HTTP/1.1 101 WebSocket Protocol Handshake\r\n' +
          'Upgrade: WebSocket\r\n' +
          'Connection: Upgrade\r\n' +
          'Sec-WebSocket-Origin: ' + websocket_origin(connection) + '\r\n' +
          'Sec-WebSocket-Location: ' + location;
.......
connection._socket.write(res, 'binary');
 

完成了握手阶段后,客户端会直接通过 socket 发送信息,而服务器也会经过服务器端socket的data 事件来获取客户端信息处理:

 

socket.on('data', function(data) {
//todo
});
 

服务器通过 socket 的 write 来向客户端浏览器发送信息,这时也要将数据用 0x00 和 0xff 包裹起来:

 

Connection.prototype.write = function(data) {
   return this.socket.write( '\u0000' + data + '\uffff');
};

 问题:

 

使用 websocket 使得客户端和服务器端都可以重用同一个 tcp 链接,不用频繁建立销毁 http 链接,并且可以避免采用 http 请求冗余的头信息,大幅提高反应速度。但是估计会降低可访问的客户端数,毕竟服务器链接有限,都被早来的客户端占完了:(

 

 

 

Refer:

 

 

flash 模拟的 websocket

nodejs 的 websocket 服务器模块

websocket 介绍

客户端html5 api w3c规范

websocket IETF通信协议

如何通过握手建立连接

 

  • 大小: 24.2 KB
  • 大小: 7.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics