HTML5之WebSocket入门3 -通信模型socket.io


Posted in Javascript onAugust 21, 2015

socket.io为什么会诞生呢?请看下面文字说明。

为什么需要socket.io?

    node.js提供了高效的服务端运行环境,但是由于浏览器端对HTML5的支持不一,为了兼容所有浏览器,提供卓越的实时的用户体验,并且为程序员提供客户端与服务端一致的编程体验,于是socket.io诞生。

    socket.io设计的目标是支持任何的浏览器,任何Mobile设备。目前支持主流的PC浏览器(IE,Safari,Chrome,Firefox,Opera等),Mobile浏览器(iphone Safari/ipad Safari/android WebKit/WebOS WebKit等)。

    socket.io基于node.js并简化了WebSocket API,统一了各种通信API。它支持:WebSocket, Flash Socket, AJAX long-polling, AJAX multipart streaming, Forever IFrame, JSONP polling。

    socket.io解决了实时的通信问题,并统一了服务端与客户端的编程方式。启动了socket以后,就像建立了一条客户端与服务端的管道,两边可以互通有无。

安装

    在命令行中执行:npm install socket.io 即可安装。

服务端编程模型

    服务端编程还是与普通服务器一样,启动服务器,提供服务,处理事件。

比如下面的server.js:

var http = require('http')
  , url = require('url')
  , fs = require('fs')
  , server;
server = http.createServer(function(req, res){
  // your normal server code
  var path = url.parse(req.url).pathname;
  switch (path){
  case '/':
   res.writeHead(200, {'Content-Type': 'text/html'});
   res.write('<h1>Hello! Try the <a href="/index.html">Socket.io Test</a></h1>');
   res.end();
   break;
  case '/index.html':
   fs.readFile(__dirname + path, function(err, data){
    if (err) return send404(res);
    res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
    res.write(data, 'utf8');
    res.end();
   });
   break;
  default: send404(res);
  }
}),
send404 = function(res){
  res.writeHead(404);
  res.write('404');
  res.end();
};
server.listen(8080);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket){
 console.log("Connection " + socket.id + " accepted.");
 socket.on('message', function(message){
    console.log("Received message: " + message + " - from client " + socket.id);
 });
 socket.on('disconnect', function(){
  console.log("Connection " + socket.id + " terminated.");
 });
});

客户端编程模型 

    客户端编程也是相似的处理方式,连接服务器,交互信息。

比如下面的index.html页面:

<!doctype html>
<html>
 <head>
  <title>Socket.io Test</title>
  <script src="/json.js"></script> <!-- for ie -->
  <script src="/socket.io/socket.io.js"></script>
 </head>
 <body>  
  <script>    
  var socket;
  var firstconnect = true;
  function connect() {
   if(firstconnect) {
    socket = io.connect(null);
    socket.on('message', function(data){ message(data); });
    socket.on('connect', function(){ status_update("Connected to Server"); });
    socket.on('disconnect', function(){ status_update("Disconnected from Server"); });
    socket.on('reconnect', function(){ status_update("Reconnected to Server"); });
    socket.on('reconnecting', function( nextRetry ){ status_update("Reconnecting in " 
     + nextRetry + " seconds"); });
    socket.on('reconnect_failed', function(){ message("Reconnect Failed"); });
    firstconnect = false;
   }
   else {
    socket.socket.reconnect();
   }
  }
  function disconnect() {
   socket.disconnect();
  }
  function message(data) {
   document.getElementById('message').innerHTML = "Server says: " + data;
  }
  function status_update(txt){
   document.getElementById('status').innerHTML = txt;
  }
  function esc(msg){
   return msg.replace(/</g, '<').replace(/>/g, '>');
  }
  function send() {
   socket.send("Hello Server!");  
  };    
  </script>
  <h1>Socket.io Test</h1>
  <div><p id="status">Waiting for input</p></div>
  <div><p id="message"></p></div> 
  <button id="connect" onClick='connect()'/>Connect</button>
  <button id="disconnect" onClick='disconnect()'>Disconnect</button>
  <button id="send" onClick='send()'/>Send Message</button>
 </body>
</html>

注意事项

1. 启动服务器还是交给node,打开命令行窗口,定位到server.js所在文件夹,输入node server.js启动服务器。

    在上面的index.html中,注意这行:<script src="/socket.io/socket.io.js"></script>。如果不想使用本地的socket.io脚本,可

以直接使用下面这个公开的脚本:

<script src="http://cdn.socket.io/stable/socket.io.js"></script>

    此外需要注意这行:socket = io.connect(null)。

这里的null代表连接本地服务,可以换成"localhost",效果也是一样的。

2. 可以使用socket.io直接启动http服务。

例如:

var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
 io.sockets.emit('this', { will: 'be received by everyone'});
});

3. socket.io可以直接通过send方法发送消息,使用message事件接收消息,例如:

//server.js
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
 socket.on('message', function () { });
});
//index.html
<script>
 var socket = io.connect('http://localhost/');
 socket.on('connect', function () {
  socket.send('hi');
  socket.on('message', function (msg) {
   // my msg
  });
 });
</script>

4. 发送和处理数据

    两端可以互发事件,互发数据,相互通信。发送事件的代码为:socket.emit(action, data, function),其中action为事件的名称,data为数据,function为回调函数;处理事件代码为:socket.on(action,function),如果emit发送的时候有数据data,则function中参数包含了这个数据。socket.io除了发送和处理内置事件,如connect, disconnect, message。还允许发送和处理自定义事件,例如:

//服务端:

io.sockets.on('connection', function (socket) {
 socket.emit('news', { hello: 'world' });
 socket.on('my other event', function (data) {
  console.log(data);
 });
});

//客户端:

<script src="/socket.io/socket.io.js"></script>
<script>
 var socket = io.connect('http://localhost');
 socket.on('news', function (data) {
  console.log(data);
  socket.emit('my other event', { my: 'data' });
 });
</script>

5. 从上面可以看出来,发送数据的时候,send和emit是都可以使用的。只不过emit更是强化了自定义事件的处理。

6. 可以在服务端使用socket的get/set方法存储客服端的相关数据,例如:

//服务端

var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
 socket.on('set nickname', function (name) {
  socket.set('nickname', name, function () { socket.emit('ready'); });
 });
 socket.on('msg', function () {
  socket.get('nickname', function (err, name) {
   console.log('Chat message by ', name);
  });
 });
});

//客户端

<script>
 var socket = io.connect('http://localhost');
 socket.on('connect', function () {
  socket.emit('set nickname', confirm('What is your nickname?'));
  socket.on('ready', function () {
   console.log('Connected !');
   socket.emit('msg', confirm('What is your message?'));
  });
 });
</script>

7. 可以广播消息,比如聊天室中给除了当前socket连接外的所有人发消息。

var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
 socket.broadcast.emit('user connected');
});

8. 可以在同一次链接中,建立多个互相独立的通道,而不是建立多次链接。这个官方叫法是“多个namespace”,比如官方的例子:

var io = require('socket.io').listen(80);
//Server
var chat = io
 .of('/chat')
 .on('connection', function (socket) {
  socket.emit('a message', {
    that: 'only'
   , '/chat': 'will get'
  });
  chat.emit('a message', {
    everyone: 'in'
   , '/chat': 'will get'
  });
 });
var news = io
 .of('/news')
 .on('connection', function (socket) {
  socket.emit('item', { news: 'item' });
 });
//Client
<script>
 var chat = io.connect('http://localhost/chat')
  , news = io.connect('http://localhost/news');
 chat.on('connect', function () {
  chat.emit('hi!');
 });
 news.on('news', function () {
  news.emit('woot');
 });
</script>

 socket.io的配置 

    socket.io的配置很简单,如果配置过express的话,你会发现它们几乎是使用差不多的方式。先看个小例子:

var io = require('socket.io').listen(80);
io.configure('production', function(){
 io.enable('browser client etag');
 io.set('log level', 1);
 io.set('transports', [
  'websocket'
 , 'flashsocket'
 , 'htmlfile'
 , 'xhr-polling'
 , 'jsonp-polling'
 ]);
});
io.configure('development', function(){
 io.set('transports', ['websocket']);
});

可以看到,socket.io使用configure, set, enable, disable进行配置。

1. 使用configure方法配置不同的运行环境下的行为;就是说在不同的环境下,启用不同的配置选项。configure的第一个参数是运行环境,第二个参数是进行配置的function。运行环境典型的如production或者是development,当然这里可以使任意的字符串。如果configure的第一个参数省略的话,说明后面的配置是公用的,不管是什么环境下,都有效。

2. 配置好各种运行环境了,那么如何设置当前运行在那个环境下呢?这个是通过在命令行中修改环境变量NODE_ENV的值实现的。

3. 在configure的配置函数中,我们可以使用set, enable, disable设置相关选项。

4. 具体可以配置的项参考:https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
实用参考

socket.io介绍:http://davidchambersdesign.com/getting-started-with-socket.io/

socket.io安装和使用说明:http://socket.io/

socket.io Wiki:https://github.com/LearnBoost/Socket.IO/wiki

Javascript 相关文章推荐
用Javascript 和 CSS 实现脚注(Footnote)效果
Sep 09 Javascript
JavaScript 模拟用户单击事件
Dec 31 Javascript
jquery中ajax学习笔记3
Oct 16 Javascript
js有关元素内容操作小结
Dec 20 Javascript
js批量设置样式的三种方法不推荐使用with
Feb 25 Javascript
javascript中常用编程知识
Apr 08 Javascript
ztree获取选中节点时不能进入可视区域出现BUG如何解决
Dec 03 Javascript
JS表格组件神器bootstrap table详解(基础版)
Dec 08 Javascript
jquery ajax双击div可直接修改div中的内容
Mar 04 Javascript
JS快速实现移动端拼图游戏
Sep 05 Javascript
详解使用vuex进行菜单管理
Dec 21 Javascript
vue项目中播放rtmp视频文件流的方法
Sep 17 Javascript
JavaScript实现为input与textarea自定义hover,focus效果的方法
Aug 21 #Javascript
IE7浏览器窗口大小改变事件执行多次bug及IE6/IE7/IE8下resize问题
Aug 21 #Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
Aug 21 #Javascript
jquery结婚电子请柬特效源码分享
Aug 21 #Javascript
js实现不提交表单获取单选按钮值的方法
Aug 21 #Javascript
JavaScript实现将数组数据添加到Select下拉框的方法
Aug 21 #Javascript
情人节单身的我是如何在敲完代码之后收到12束玫瑰的(javascript)
Aug 21 #Javascript
You might like
文章推荐系统(三)
2006/10/09 PHP
phpmyadmin config.inc.php配置示例
2013/08/27 PHP
composer.lock文件的作用
2016/02/03 PHP
javascript相等运算符与等同运算符详细介绍
2013/11/09 Javascript
jquery使用each方法遍历json格式数据实例
2015/05/18 Javascript
ECMAScript6新增值比较函数Object.is
2015/06/12 Javascript
javascript实现PC网页里的拖拽效果
2016/03/14 Javascript
javascript设计模式之中介者模式学习笔记
2017/02/15 Javascript
jQuery插件FusionWidgets实现的Cylinder图效果示例【附demo源码】
2017/03/23 jQuery
js实现抽奖效果
2017/03/27 Javascript
JS图片轮播与索引变色功能实例详解
2017/07/06 Javascript
微信JSSDK调用微信扫一扫功能的方法
2017/07/25 Javascript
nodejs简单实现TCP服务器端和客户端的聊天功能示例
2018/01/04 NodeJs
深入浅出理解JavaScript高级定时器原理与用法
2018/08/02 Javascript
JavaScript继承与聚合实例详解
2019/01/22 Javascript
webpack4实现不同的导出类型
2019/04/09 Javascript
ckeditor一键排版功能实现方法分析
2020/02/06 Javascript
Vue中通过vue-router实现命名视图的问题
2020/04/23 Javascript
javascript使用canvas实现饼状图效果
2020/09/08 Javascript
python实现根据月份和日期得到星座的方法
2015/03/27 Python
Python三级目录展示的实现方法
2016/09/28 Python
Python实现的NN神经网络算法完整示例
2018/06/19 Python
Python3.x+pyqtgraph实现数据可视化教程
2020/03/14 Python
Python代码执行时间测量模块timeit用法解析
2020/07/01 Python
python实现计算器简易版
2020/12/17 Python
python time.strptime格式化实例详解
2021/02/03 Python
CSS3中各种颜色属性的使用教程
2016/05/17 HTML / CSS
HTML5头部标签的一些常用信息小结
2016/10/23 HTML / CSS
工程业务员工作职责
2013/12/07 职场文书
医药个人求职信范文
2014/01/29 职场文书
标准自荐信范文
2014/01/29 职场文书
小学安全教育材料
2014/02/17 职场文书
争先创优公开承诺书
2014/08/30 职场文书
汤姆索亚历险记读书笔记
2015/06/29 职场文书
如何理解Vue简单状态管理之store模式
2021/05/15 Vue.js
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android