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的单例模式 (singleton in Javascript)
Jun 11 Javascript
什么是DOM(Document Object Model)文档对象模型
Mar 05 Javascript
ScrollDown的基本操作示例
Jun 09 Javascript
一个支持任意尺寸的图片上下左右滑动效果
Aug 24 Javascript
HTML5使用DeviceOrientation实现摇一摇功能
Jun 05 Javascript
详解jQuery向动态生成的内容添加事件响应jQuery live()方法
Nov 02 Javascript
jQuery简单实现iframe的高度根据页面内容自适应的方法
Aug 01 Javascript
JavaScript实现解析INI文件内容的方法
Nov 17 Javascript
详解angularJS动态生成的页面中ng-click无效解决办法
Jun 19 Javascript
解决vue中的无限循环问题
Jul 27 Javascript
javascript this指向相关问题及改变方法
Nov 19 Javascript
让JavaScript代码更加精简的方法技巧
Jun 01 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
preg_match_all使用心得分享
2014/01/31 PHP
PHP中file_exists使用中遇到的问题小结
2016/04/05 PHP
Laravel 5.3 学习笔记之 安装
2016/08/28 PHP
Yii框架getter与setter方法功能与用法分析
2019/10/22 PHP
php-7.3.6 编译安装过程
2020/02/11 PHP
JS 巧妙获取剪贴板数据 Excel数据的粘贴
2009/07/09 Javascript
js中的referrer返回上一页使用介绍
2013/09/26 Javascript
基于Jquery和html5的7款个性化地图插件
2015/11/17 Javascript
Jquery实现仿京东商城省市联动菜单
2015/11/19 Javascript
js实现的页面矩阵图形变换特效
2016/01/26 Javascript
JS去除重复并统计数量的实现方法
2016/12/15 Javascript
详解Jquery EasyUI tree 的异步加载(遍历指定文件夹,根据文件夹内的文件生成tree)
2017/02/11 Javascript
js学习总结之dom2级事件基础知识详解
2017/07/27 Javascript
详解JS中的柯里化(currying)
2017/08/17 Javascript
React 源码中的依赖注入方法
2018/11/07 Javascript
Angular7创建项目、组件、服务以及服务的使用
2019/02/19 Javascript
Vue.js中该如何自己维护路由跳转记录
2019/05/19 Javascript
js实现鼠标点击页面弹出自定义文字效果
2019/12/24 Javascript
Vue Router中应用中间件的方法
2020/08/06 Javascript
Python爬取Coursera课程资源的详细过程
2014/11/04 Python
python 实现网上商城,转账,存取款等功能的信用卡系统
2016/07/15 Python
Django查询数据库的性能优化示例代码
2017/09/24 Python
浅谈Python实现2种文件复制的方法
2018/01/19 Python
利用Python如何实现数据驱动的接口自动化测试
2018/05/11 Python
几行Python代码爬取3000+上市公司的信息
2019/01/24 Python
Python小白必备的8个最常用的内置函数(推荐)
2019/04/03 Python
Pytorch训练过程出现nan的解决方式
2020/01/02 Python
使用TensorFlow直接获取处理MNIST数据方式
2020/02/10 Python
Python虚拟环境的创建和包下载过程分析
2020/06/19 Python
俄罗斯品牌服装和鞋子的在线商店:KUPIVIP
2019/10/27 全球购物
接待员岗位责任制
2014/02/10 职场文书
暑期研修感言
2014/02/17 职场文书
介绍信范文
2015/01/31 职场文书
2015年董事长秘书工作总结
2015/07/23 职场文书
浅谈Python响应式类库RxPy
2021/06/14 Python
详细聊聊关于Mysql联合查询的那些事儿
2021/10/24 MySQL