WebSocket教程

一、为什么需要 WebSocket?

初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?

答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。

举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

 

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。

 

二、简介

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。


ws://example.com:80/some/path

 

三、客户端的简单示例

WebSocket 的用法相当简单。

下面是一个网页脚本的例子(点击这里看运行结果),基本上一眼就能明白。


var ws = new WebSocket("wss://echo.websocket.org");ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!");
};ws.onmessage = function(evt) {console.log( "Received Message: " + evt.data);ws.close();
};ws.onclose = function(evt) {console.log("Connection closed.");
};      

 

四、客户端的 API

WebSocket 客户端的 API 如下。

4.1 WebSocket 构造函数

WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例。


var ws = new WebSocket('ws://localhost:8080');

执行上面语句之后,客户端就会与服务器进行连接。

实例对象的所有属性和方法清单,参见这里。

4.2 webSocket.readyState

readyState属性返回实例对象的当前状态,共有四种。

  • CONNECTING:值为0,表示正在连接。
  • OPEN:值为1,表示连接成功,可以通信了。
  • CLOSING:值为2,表示连接正在关闭。
  • CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

下面是一个示例。


switch (ws.readyState) {case WebSocket.CONNECTING:// do somethingbreak;case WebSocket.OPEN:// do somethingbreak;case WebSocket.CLOSING:// do somethingbreak;case WebSocket.CLOSED:// do somethingbreak;default:// this never happensbreak;
}

4.3 webSocket.onopen

实例对象的onopen属性,用于指定连接成功后的回调函数。


ws.onopen = function () {ws.send('Hello Server!');
}

如果要指定多个回调函数,可以使用addEventListener方法。


ws.addEventListener('open', function (event) {ws.send('Hello Server!');
});

4.4 webSocket.onclose

实例对象的onclose属性,用于指定连接关闭后的回调函数。


ws.onclose = function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event
};ws.addEventListener("close", function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event
});

4.5 webSocket.onmessage

实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。


ws.onmessage = function(event) {var data = event.data;// 处理数据
};ws.addEventListener("message", function(event) {var data = event.data;// 处理数据
});

注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)。


ws.onmessage = function(event){if(typeof event.data === String) {console.log("Received data string");}if(event.data instanceof ArrayBuffer){var buffer = event.data;console.log("Received arraybuffer");}
}

除了动态判断收到的数据类型,也可以使用binaryType属性,显式指定收到的二进制数据类型。


// 收到的是 blob 数据
ws.binaryType = "blob";
ws.onmessage = function(e) {console.log(e.data.size);
};// 收到的是 ArrayBuffer 数据
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {console.log(e.data.byteLength);
};

4.6 webSocket.send()

实例对象的send()方法用于向服务器发送数据。

发送文本的例子。


ws.send('your message');

发送 Blob 对象的例子。


var file = document.querySelector('input[type="file"]').files[0];
ws.send(file);

发送 ArrayBuffer 对象的例子。


// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {binary[i] = img.data[i];
}
ws.send(binary.buffer);

4.7 webSocket.bufferedAmount

实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。


var data = new ArrayBuffer(10000000);
socket.send(data);if (socket.bufferedAmount === 0) {// 发送完毕
} else {// 发送还没结束
}

4.8 webSocket.onerror

实例对象的onerror属性,用于指定报错时的回调函数。


socket.onerror = function(event) {// handle error event
};socket.addEventListener("error", function(event) {// handle error event
});

 

五、服务端的实现

WebSocket 服务器的实现,可以查看维基百科的列表。

常用的 Node 实现有以下三种。

  • µWebSockets
  • Socket.IO
  • WebSocket-Node

具体的用法请查看它们的文档,这里不详细介绍了。

 

六、WebSocketd

下面,我要推荐一款非常特别的 WebSocket 服务器:Websocketd。

它的最大特点,就是后台脚本不限语言,标准输入(stdin)就是 WebSocket 的输入,标准输出(stdout)就是 WebSocket 的输出。

举例来说,下面是一个 Bash 脚本counter.sh


#!/bin/bashecho 1
sleep 1echo 2
sleep 1echo 3

命令行下运行这个脚本,会输出1、2、3,每个值之间间隔1秒。


$ bash ./counter.sh
1
2
3

现在,启动websocketd,指定这个脚本作为服务。


$ websocketd --port=8080 bash ./counter.sh

上面的命令会启动一个 WebSocket 服务器,端口是8080。每当客户端连接这个服务器,就会执行counter.sh脚本,并将它的输出推送给客户端。


var ws = new WebSocket('ws://localhost:8080/');ws.onmessage = function(event) {console.log(event.data);
};

上面是客户端的 JavaScript 代码,运行之后会在控制台依次输出1、2、3。

有了它,就可以很方便地将命令行的输出,发给浏览器。


$ websocketd --port=8080 ls

上面的命令会执行ls命令,从而将当前目录的内容,发给浏览器。使用这种方式实时监控服务器,简直是轻而易举(代码)。

更多的用法可以参考官方示例。

  • Bash 脚本读取客户端输入的例子
  • 五行代码实现一个最简单的聊天服务器

websocketd 的实质,就是命令行的 WebSocket 代理。只要命令行可以执行的程序,都可以通过它与浏览器进行 WebSocket 通信。下面是一个 Node 实现的回声服务greeter.js


process.stdin.setEncoding('utf8');process.stdin.on('readable', function() {var chunk = process.stdin.read();if (chunk !== null) {process.stdout.write('data: ' + chunk);}
});

启动这个脚本的命令如下。


$ websocketd --port=8080 node ./greeter.js

官方仓库还有其他各种语言的例子。

 

七、参考链接

  • How to Use WebSockets
  • WebSockets - Send & Receive Messages
  • Introducing WebSockets: Bringing Sockets to the Web

(完)

 

原文链接:http://www.ruanyifeng.com/blog/2017/05/websocket.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282234.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# WPF十个美观的界面设计展示

概述很多时候&#xff0c;我们设计的界面总是感觉缺乏美感&#xff0c;不是我们不会开发好看的界面&#xff0c;而是不知道怎么才算美观&#xff0c;这时候我们不妨看看别人好的页面是怎么做的.下面展示一些我觉得做的比较好的cs界面&#xff0c;希望能给大家在平时做界面设计时…

MySQL5.6二进制软件包编译安装详解(三)

一、软件环境 [rootlocalhost ~]# uname -r 3.10.0-862.el7.x86_64 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) 二、安装部署过程详解 MySQL安装3种方式&#xff1a;1>rpm包安装应用文件默认安装在/usr/local 目录下2>源码编译需…

使用autok3s 安装k3s 集群 和 kuboard 管理集群

一、k3s介绍1.1 什么是k3s?k3s 是经过 CNCF 认证的由 Rancher 公司开发维护的一个轻量级的 Kubernetes 发行版&#xff0c;内核机制还是和 k8s 一样&#xff0c;但是剔除了很多外部依赖以及 K8s 的 alpha、beta 特性&#xff0c;同时改变了部署方式和运行方式&#xff0c;目的…

社区纠纷不断:程序员何苦为难程序员

出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013)今年年初&#xff0c;我们报道“因为被多人侮辱大吼&#xff0c;Swift 之父正式退出 Swift 核心团队”。诸如此类的“语言暴力”、“网络暴力”事件在开源社区乃至整个 IT 社区屡见不鲜。多个技术社区&#xff0c;都出…

PHP 分布式集群中session共享问题以及session有效期的设置

一、Session的原理 以下以默认情况举例&#xff1a; session_start();之后&#xff0c;会生成一个唯一的session_id&#xff0c;每一个用户对应唯一一个session_id&#xff0c;每一个session_id对应服务器端的一个session文件。这个session文件存储着当前session_id的信息&am…

[SDOI2009]Bill的挑战——全网唯一 一篇容斥题解

全网唯一一篇容斥题解 Description Solution 看到这个题&#xff0c;大部分人想的是状压dp 但是我是个蒟蒻没想到&#xff0c;就用容斥切掉了。 并且复杂度比一般状压低&#xff0c; &#xff08;其实这个容斥的算法&#xff0c;提出来源于ywy_c_asm&#xff09; &#xff08;然…

对象存储OSS服务

一、oss是什么 阿里云对象存储服务&#xff08;Object Storage Service&#xff0c;简称OSS&#xff09;为您提供基于网络的数据存取服务。使用OSS&#xff0c;您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种非结构化数据文件。 阿里云OSS将数据文件以…

《Access 2007开发指南(修订版)》一一1.5 什么是数据库对象

本节书摘来自异步社区出版社《Access 2007开发指南(修订版)》一书中的第1章&#xff0c;第1.5节&#xff0c;作者&#xff1a; 【美】Alison Balter&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.5 什么是数据库对象 Access 2007开发指南(修订版)正如前…

ETL工具kettle的组件--生成记录

今天介绍下kettle的一个比较实用的组件——生成记录&#xff1b;当我们想将一部分文本数据变成数据行&#xff0c;每个字段作为一个数据行的一个列&#xff0c;那么我们可以利用这个组件&#xff1b;它的位置在双击点开根据自己的实际需要进行设置当设置后&#xff0c;可以点击…

Linux学习笔记一

linux  kernel lib module shell tools ls -la&#xff1a; 显示所有文件包括隐藏文件  cat /proc/cpuinfo&#xff1a; 显示cpu信息 man man  /string&#xff1a; 向上搜索string字符串 继续按下小写n向上搜索  ?string&#xff1a; 向下搜索string字符串 继续按下大…

PHP中路由和rewrite的使用

一、场景介绍&#xff1a; 1、简化url地址&#xff0c;方便大家记忆 2、有利于搜索引擎优化 3、安全&#xff08;让用户看不出网站的目录结构&#xff09; 举例&#xff1a;比如我这里将main控制器中的bb方法路由到kk&#xff0c;这样&#xff0c;我们a标签请求跳转到cp.xi…

《NoSQL权威指南》导读

引言 NoSQL权威指南“没有什么会比引入新秩序更难&#xff0c;因为创新者必须要面对那些在旧环境中已经做得很好的对手&#xff0c;以及那些在新环境中做得很好的冷漠者。” ——Niccolo Machiavelli [1] 在过去的几十年&#xff0c;我已经通过Elsevier/Morgan Kaufmann出版社出…

PHP开发常见功能实现流程

一、pc端网站登录 1、获取并过滤用户提交的用户名和密码以及验证码 2、验证用户提交验证码和session中的验证码是否一致 3、验证用户名是否存在 4、根据用户名获取密码&#xff0c;并校验密码是否一致 5、密码一致&#xff0c;则登录成功&#xff0c;跳转到对应的首页 图示…

七牛直播云服务技术揭秘

以下根据七牛云首席布道师何李石现场演讲内容整理。 直播模型及其实现 一个通用的直播模型一般包括三个模块&#xff1a;主播方、服务器端和播放端。 首先是主播方&#xff0c;它是产生视频流的源头&#xff0c;由一系列流程组成&#xff1a; 第一&#xff0c;通过一定的设备来…

golang 标准库间依赖的可视化展示

简介 国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内容,网上也要讨论,但是没有发现直接能拿过来用的.标准库之间,是必然存在依赖关系的,不同库被依赖的程…

《HTML5 2D游戏编程核心技术》——第1章,第1.3节特别功能

本节书摘来自华章出版社《HTML5 2D游戏编程核心技术》一书中的第1章&#xff0c;第1.3节特别功能&#xff0c;作者&#xff3b;美&#xff3d; 戴维吉尔里&#xff0c;更多章节内容可以访问云栖社区“华章计算机”公众号查看。 1.3 特别功能 Snail Bait游戏有3个特别的功能&a…

XunSearch的安装和加入服务器开机脚本以及将目录写入系统变量

一、安装xunserach 1、cd ~ 2、wget http://www.xunsearch.com/download/xunsearch-full-latest.tar.bz2 #下载最新xunsearch包 3、tar -xjf xunsearch-full-latest.tar.bz2 #解压xunsearch包 4、cd xunsearch-full-1.4.11/ #进入xunsearch包目录 5、sh setup.sh #执…

dubbo源码解析-zookeeper创建节点

前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码解析-zookeeper连接中已经讲到,这周解析的是另一道,即服务提供者能实现失效踢出是根据什么原…

配置mysql为主主复制步骤

mysql版本&#xff1a;mysql-5.6.24-solaris10-sparc-64bit.tar 操作系统&#xff1a;solaris 11g u10 操作用户&#xff1a;使用非root进行操作安装&#xff0c;a路服务器ip地址为192.168.1.1 b路ip地址为192.168.1.2&#xff08;应改为实际ip地址&#xff09; 1&#xff0c;安…

XunSearch的使用

一、项目的配置文件 1、要想使用xunsearch&#xff0c;首先需要进行配置文件的配置。 默认目录在app下&#xff0c;如下面的结构&#xff0c;每一个搜索项目都需要有一个ini文件进行相应的配置。 举例&#xff1a; project.name novel project.default_charset utf-8 serv…