websocket简介:

WebSocket协议是 HTML5 开始提供的一种基于TCP的一种新的全双工通讯的网络通讯协议。它允许服务器主动发送信息给客户端

和http协议的不同??

HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。而这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。

简单的说,WebSocket协议之前,实现双工通信就是通过不停发送HTTP请求(长轮询,使用 Ajax 轮询技术,轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求),从服务器拉取更新来实现,这导致了效率低下,浪费带宽资源,WebSocket解决了这个问题。

WebSocket 就是这样发明的。WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。

websocket如何工作??

在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为"握手" 。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

以下 API 用于创建 WebSocket 对象。第一个参数 url, 指定连接的 URL。而URL参数需要以WS://或者WSS://开头,例如:ws://www.websocket.org,如果URL有语法错误,构造函数会抛出异常。第二个参数 protocol 是可选的,指定了可接受的子协议。议的参数例如XMPP(Extensible Messaging and Presence Protocol)、SOAP(Simple Object Access Protocol)或者自定义协议。  第二个参数是协议名称,是可选的,服务端和客服端使用的协议必须一致,这样收发消息彼此才能理解,你可以定义一个或多个客户端使用的协议,服务端会选择一个来使用,一个客服端和一个服务端之间只能有一个协议

var Socket = new WebSocket(url, [protocol] );

注意:基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。任何实际的 WebSockets 服务器端实现都需要一个异步服务器。

目前大部分浏览器支持 WebSocket() 接口,如 Chrome, Mozilla, Opera 和 Safari。

WS和WSS的区别??

注意:WebSocket协议定义了两种URL方案,WS和WSS分别代表了客户端和服务端之间未加密和加密的通信。WS(WebSocket)类似于Http URL,而WSS(WebSocket Security)URL 表示连接是基于安全传输层(TLS/SSL)和https的连接是同样的安全机制。

websocket的属性、事件、方法

属性 描述
Socket.readyState

只读属性 readyState 表示连接状态,可以是以下值:

0 - 表示连接尚未建立。

1 - 表示连接已建立,可以进行通信。

2 - 表示连接正在进行关闭。

3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount

只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

注意:上述readyState 属性用于表示链接状态!

事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发
方法 描述
Socket.send()

使用连接发送数据

Socket.close()

关闭连接

websocket+nodejs简单实例应用

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

WebSocket API是纯事件驱动,一旦建立全双工连接,当服务端给客户端发送数据或者资源,它能自动发送状态改变的数据和通知。所以你不需要为了状态的更新而去轮训Server,在客户端监听即可。

websocket客户端:

<!DOCTYPE HTML>
<html><head><meta charset="utf-8"><title>websocket测试(runoob.com)</title><script type="text/javascript">function WebSocketTest(){if ("WebSocket" in window){alert("您的浏览器支持 WebSocket!");// 初始化一个 WebSocket 对象,参数指明urlvar ws = new WebSocket("ws://localhost:9999");// WebSocket 连接时候触发ws.onopen = function(){//使用 send() 方法发送数据ws.send("客户端发送的数据");alert("数据发送中...");};// 接收服务端数据时触发ws.onmessage = function (evt) { var received_msg = evt.data;console.log(received_msg);alert("数据已接收...");};//断开 web socket 连接成功触发事件ws.onclose = function(){ // 关闭 websocketalert("连接已关闭..."); };}else{// 浏览器不支持 WebSocketalert("您的浏览器不支持 WebSocket!");}}</script></head><body><div id="sse"><a href="javascript:WebSocketTest()">运行 WebSocket</a></div></body>
</html>

websocket服务端:

WebSocket 在服务端的实现非常丰富。Node.js、Java、C++、Python 等多种语言都有自己的解决方案。这里主要记录nodejs作为websocket服务端的解决方案。

Node 实现有以下三种。

  • µWebSockets
  • Socket.IO
  • WebSocket-Node

这里主要记录使用nodejs搭建websocket服务器的方案

ws 是nodejs的一个WebSocket库,可以用来创建服务。使用cnpm install ws 命令行进行安装

下面是server.js的文件内容,cmd转到文件目录运行 node server.js  命令行

var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ port: 9999 });
wss.on('connection', function (ws) {console.log('client connected');ws.on('message', function (message) {console.log(message);ws.send("服务端接收到请求后,发送给客户端的数据");});});

效果如下:

进阶:websocket+nodejs模拟股票实例

上面的例子很简单,只是为了演示如何运用nodejs的ws创建一个WebSocket服务器。且可以接受客户端的消息。那么下面这个例子演示股票的实时更新。客服端只需要连接一次,服务器端会不断地发送新数据,客户端收数据后更新UI.页面如下,有五只股票,开始和停止按钮测试连接和关闭。

注意:一定要先在项目文件夹下运行 cnpm install ws  安装wwebsocket依赖包,不然会报以下错误

服务端server.js文件内容如下:

//引入websocket 的ws模块
var WebSocketServer = require('ws').Server,//初始化websocket对象
wss = new WebSocketServer({ port: 8181 });//初始数据对象
var stocks = {"AAPL": 95.0,"MSFT": 50.0,"AMZN": 300.0,"GOOG": 550.0,"YHOO": 35.0
}//获取随机数据的函数
function randomInterval(min, max) {return Math.floor(Math.random() * (max - min + 1) + min);
}//定时器返回的句柄
var stockUpdater;
var randomStockUpdater=function(){for (var symbol in stocks) {  //遍历对象属性进行随机增加浮动数值if(stocks.hasOwnProperty(symbol)) {   //遍历对象非继承属性var randomizedChange = randomInterval(-150, 150);var floatChange = randomizedChange / 100;stocks[symbol] += floatChange;}}//随机时间间隔,获取一个数据区间中的随机数值var randomMSTime = randomInterval(500, 2500);  stockUpdater = setTimeout(function() {   //模拟股票数据变化,随机更改对象属性值randomStockUpdater();}, randomMSTime);}//执行模拟数据变化更新
randomStockUpdater();//声明clientStocks接收客户端数据
var clientStocks = [];//连接建立后
wss.on('connection', function (ws) {//定义数据更新函数var sendStockUpdates = function (ws) {if (ws.readyState == 1) {  //readyState为1表示已经建立连接var stocksObj = {};for (var i = 0; i < clientStocks.length; i++) {var symbol = clientStocks[i];stocksObj[symbol] = stocks[symbol];}if (stocksObj.length !== 0) {  //数据包内容不为空时将数据响应给客户端ws.send(JSON.stringify(stocksObj));//需要将对象转成字符串。WebSocket只支持文本和二进制数据console.log("更新", JSON.stringify(stocksObj));}}}//服务器端定时更新响应数据var clientStockUpdater = setInterval(function () {sendStockUpdates(ws);}, 1000);//服务器端接收到客户端发送过来的数据,根据请求的数据更新响应数据ws.on('message', function (message) {var stockRequest = JSON.parse(message);console.log("服务器收到的消息:", stockRequest);clientStocks = stockRequest['stocks'];sendStockUpdates(ws);});});

客户端client.html 文件如下,界面使用了和jquery和bootstrape框架

<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>WebSocket  Demo</title><meta name="viewport" content="width=device-width, initial-scale=1"/><link href="../bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" /><script src="../js/jquery-1.12.3.min.js"></script><script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script>
</head><body>
<div class="vertical-center"><div class="container"><h1>Stock Chart over WebSocket</h1><button class="btn btn-primary">开始</button><button class="btn btn-danger">停止</button><table class="table" id="stockTable"><thead><tr><th>Symbol</th><th>Price</th></tr></thead><tbody id="stockRows"><tr><td><h3>AAPL</h3></td><td id="AAPL"><h3><span class="label label-default">95.00</span></h3></td></tr><tr><td><h3>MSFT</h3></td><td id="MSFT"><h3><span class="label label-default">50.00</span></h3></td></tr><tr><td><h3>AMZN</h3></td><td id="AMZN"><h3><span class="label label-default">300.00</span></h3></td></tr><tr><td><h3>GOOG</h3></td><td id="GOOG"><h3><span class="label label-default">550.00</span></h3></td></tr><tr><td><h3>YHOO</h3></td><td id="YHOO"><h3><span class="label label-default">35.00</span></h3></td></tr></tbody></table></div>
</div><script>//客户端初始化websocket对象var ws = new WebSocket("ws://localhost:9999");//客户端发送的请求对象var stock_request = { "stocks": ["AAPL", "MSFT", "AMZN", "GOOG", "YHOO"] };var isClose = false; //通讯连接是否被关闭//界面的初始化数据对象var stocks = {"AAPL": 0, "MSFT": 0, "AMZN": 0, "GOOG": 0, "YHOO": 0};//定义更新UI界面的函数function updataUI() {//websocket连接上时触发ws.onopen = function (e) {console.log('Connection to server opened');isClose = false;ws.send(JSON.stringify(stock_request));console.log("sened a mesg");}// UI update functionvar changeStockEntry = function (symbol, originalValue, newValue) {var valElem = $('#' + symbol + ' span');valElem.html(newValue.toFixed(2)); //toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。if (newValue < originalValue) {valElem.addClass('label-danger');valElem.removeClass('label-success');} else if (newValue > originalValue) {valElem.addClass('label-success');valElem.removeClass('label-danger');}}// websocket接收到服务端数据时触发ws.onmessage = function (e) {var stocksData = JSON.parse(e.data);  //字符串转JSON对象console.log(stocksData);for (var symbol in stocksData) {  //遍历对象属性,更改客户端界面数据if (stocksData.hasOwnProperty(symbol)) {changeStockEntry(symbol, stocks[symbol], stocksData[symbol]);stocks[symbol] = stocksData[symbol];}}};}updataUI();  //更新UI界面$(".btn-primary").click(function() {  //开始按钮点击可以在断开后重连websocketif (isClose) {ws = new WebSocket("ws://localhost:9999");}updataUI();  //重连后更新UI界面});$(".btn-danger").click(function() {  //断开按钮可以关闭websocket连接ws.close();});//触发websocket连接关闭事件ws.onclose = function (e) {console.log("Connection closed", e);isClose = true;};</script>
</body>
</html>

源码见文章底部链接,效果如下:

进阶:websocket+nodejs模拟聊天室实例

上面的例子是连接建立之后,服务端不断给客户端发送数据。接下来例子是一个简单的聊天室类的例子。可以建立多个连接。

1.安装node-uuid模块,用来给每个连接一个唯一号。

2、客户端代码如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>WebSocket Echo Demo</title><meta name="viewport" content="width=device-width, initial-scale=1"/><link href="../bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" /><script src="../js/jquery-1.12.3.min.js"></script><script src="../js/jquery-1.12.3.min.js"></script><script src="../bootstrap-3.3.5/js/bootstrap.min.js"></script><script>//建立连接var ws = new WebSocket("ws://localhost:8181");var nickname = "";ws.onopen = function (e) {console.log('Connection to server opened');}//显示函数,根据客户端接收到的数据类型进行ui界面显示function appendLog(type, nickname, message) {if (typeof message == "undefined") return;var messages = document.getElementById('messages');var messageElem = document.createElement("li");var preface_label;if (type === 'notification') {preface_label = "<span class=\"label label-info\">*</span>";} else if (type == 'nick_update') {preface_label = "<span class=\"label label-warning\">*</span>";} else {preface_label = "<span class=\"label label-success\">"+ nickname + "</span>";}var message_text = "<h2>" + preface_label + "&nbsp;&nbsp;"+ message + "</h2>";messageElem.innerHTML = message_text;messages.appendChild(messageElem);}//收到消息处理ws.onmessage = function (e) {var data = JSON.parse(e.data);nickname = data.nickname;appendLog(data.type, data.nickname, data.message);console.log("ID: [%s] = %s", data.id, data.message);}ws.onclose = function (e) {appendLog("Connection closed");console.log("Connection closed");}//发送消息function sendMessage() {var messageField = document.getElementById('message');if (ws.readyState === WebSocket.OPEN) {ws.send(messageField.value);}messageField.value = '';messageField.focus();}//修改名称function changName() {var name = $("#name").val();if (ws.readyState === WebSocket.OPEN) {ws.send("/nick " + name);}}function disconnect() {ws.close();}</script>
</head><body ><div class="vertical-center"><div class="container"><ul id="messages" class="list-unstyled"></ul><hr/><form role="form" id="chat_form" onsubmit="sendMessage(); return false;"><div class="form-group"><input class="form-control" type="text" id="message" name="message"placeholder="Type text to echo in here" value="" autofocus/></div><button type="button" id="send" class="btn btn-primary"onclick="sendMessage();">Send Message</button></form><div class="form-group"><span>nikename:</span><input id="name" type="text" /> <button class="btn btn-sm btn-info" onclick="changName();">change</button></div></div></div>
</body>
</html>

3、服务端代码如下:

//引入ws模块,初始化websocket服务端
var WebSocket = require('ws');
var WebSocketServer = WebSocket.Server,
wss = new WebSocketServer({ port: 8181 });//引入node-uuid模块,唯一标识
var uuid = require('node-uuid');//客户端数组
var clients = [];//遍历所有客户端连接,依次下发数据
function wsSend(type, client_uuid, nickname, message) {for (var i = 0; i < clients.length; i++) {var clientSocket = clients[i].ws;if (clientSocket.readyState === WebSocket.OPEN) {clientSocket.send(JSON.stringify({ //websocket传递JSONA字符串格式"type": type,"id": client_uuid,"nickname": nickname,"message": message}));}}
}var clientIndex = 1;//每一个客户端和服务端建立连接时触发
wss.on('connection', function(ws) {var client_uuid = uuid.v4();  //获取随机唯一标识var nickname = "AnonymousUser" + clientIndex;clientIndex += 1;clients.push({ "id": client_uuid, "ws": ws, "nickname": nickname });console.log('client [%s] connected', client_uuid);var connect_message = nickname + " has connected";wsSend("notification", client_uuid, nickname, connect_message);console.log('client [%s] connected', client_uuid);ws.on('message', function(message) {if (message.indexOf('/nick') === 0) { //json字符串数据包含修改昵称的数据时var nickname_array = message.split(' ');if (nickname_array.length >= 2) {var old_nickname = nickname;nickname = nickname_array[1];var nickname_message = "Client " + old_nickname + " changed to " + nickname;wsSend("nick_update", client_uuid, nickname, nickname_message);}} else {wsSend("message", client_uuid, nickname, message);}});//断开指定uuid的连接var closeSocket = function(customMessage) {for (var i = 0; i < clients.length; i++) {if (clients[i].id == client_uuid) {var disconnect_message;if (customMessage) {disconnect_message = customMessage;} else {disconnect_message = nickname + " has disconnected";}wsSend("notification", client_uuid, nickname, disconnect_message);clients.splice(i, 1);}}};//某个客户端连接断开时触发ws.on('close', function () {closeSocket();});//SIGINT这个信号是系统默认信号,代表信号中断,就是ctrl+cprocess.on('SIGINT', function () {console.log("Closing things");closeSocket('Server has disconnected');process.exit();});
});

效果如下:

源码见文章尾部

上述代码实现了一个服务器下的多个客户端连接,单并没有实现客户端的及时通讯,比如微信和QQ的单聊和群聊效果,可以参考以下demo

参考网址:https://blog.csdn.net/CJXBShowZhouyujuan/article/details/77816944

node-uuid是什么??

nodejs生成UID(唯一标识符)——node-uuid模块

unique identifier 惟一标识符        -->> uid

在项目开发中我们常需要给某些数据定义一个唯一标识符,便于寻找,关联。node-uuid模块很好的提供了这个功能。

使用起来很简单,两种:

1、uuid.v1(); -->基于时间戳生成  (time-based)

2、uuid.v4(); -->随机生成  (random)

通常我们使用基于时间戳  v1()  生成的UID,随机生成  v4()  还是有一定几率重复的。

    var UUID = require('uuid');var ID = UUID.v1();

websocket 和 socket 的区别??

软件通信有七层结构,下三层结构偏向与数据通信,上三层更偏向于数据处理,中间的传输层则是连接上三层与下三层之间的桥梁,每一层都做不同的工作,上层协议依赖与下层协议。基于这个通信结构的概念。

Socket 其实并不是一个协议,是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口。当两台主机通信时,让 Socket 去组织数据,以符合指定的协议。TCP 连接则更依靠于底层的 IP 协议,IP 协议的连接则依赖于链路层等更低层次。

WebSocket 则是一个典型的应用层协议。

总的来说:Socket 是传输控制层协议,WebSocket 是应用层协议。

源码:http://pan.baidu.com/s/1c2FfKbA

或 百度链接:https://pan.baidu.com/s/1cabjJKikHC3xBW-qUtP-3g   提取码:yb4u

参考网址:

https://www.cnblogs.com/stoneniqiu/p/5402311.html

http://www.runoob.com/html/html5-websocket.html

websocket 学习--简单使用,nodejs搭建websocket服务器,到模拟股票,到实现聊天室相关推荐

  1. websocket 获取连接id_Swoole学习笔记七:搭建WebSocket长连接 之 使用 USER_ID 作为身份凭证...

    Swoole学习笔记七:搭建WebSocket长连接 之 使用 USER_ID 作为身份凭证 2年前 阅读 3678 评论 0 喜欢 0 ### 0.前言 前面基本的WebSocket操作,我们基本都 ...

  2. wss2016 作文件服务器,Nodejs搭建wss服务器教程

    本文为大家分享了Nodejs搭建wss服务器的教程,供大家参考,具体内容如下 首先使用OpenSSL创建自签名证书: #生成私钥key文件 openssl genrsa 1024 > /path ...

  3. 通过nodejs搭建HTTP服务器

    文章目录 通过nodejs搭建HTTP服务器 前提 搭建步骤 实例 启动服务器 通过nodejs搭建HTTP服务器 nodejs是一个用于解析执行javaScript代码的环境(它不是语言,不是框架) ...

  4. Esp8266进阶之路12 图文并茂学习阿里云主机搭建8266MQTT服务器,实现移动网络远程控制一盏灯!

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个"hello ...

  5. svn服务器搭建和使用_简单使用nodejs搭建一个静态服务器

    前提:系统安装nodejs 搭建步骤 使用nodejs搭建服务器,简单的来说可以分为三步: require相应的模块 创建服务器 配置端口 启动服务器 必要的nodejs模块 以下模块都是以 var ...

  6. 操作系统学习3--Windows server 2012搭建web服务器

    Windows server 2012搭建web服务器 经过前面的铺垫,我们对win server一些基础特性都有了简单的了解,win server可以作为dhcp和dns服务器,也能做一个web服务 ...

  7. node.js 微信小程序 部署服务器_微信小程序开发入门(一),Nodejs搭建本地服务器...

    1.  如何模拟真实环境中,读取服务端数据,首先需要使用Nodejs搭建一个本地服务器的环境. 在搭建web服务器之前,需要先安装node.js(安装版本最好为6.9.x) 安装后node.js,接下 ...

  8. 用nodejs搭建web服务器

    转自:微点阅读 https://www.weidianyuedu.com Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动. ...

  9. node制作http服务器,NodeJS 搭建 HTTP 服务器

    前言 在 NodeJS 中用来创建服务的模块是 http 核心模块,本篇就来介绍关于使用 http 模块搭建 HTTP 服务器和客户端的方法,以及模块的基本 API. HTTP 服务器 1.创建 HT ...

最新文章

  1. Javascript学习--------详解window窗口对象
  2. python学习笔记 -- reduce合并减少
  3. 如何用CS07进行BOM工厂分配
  4. 自嗨锅要持续嗨,还得碾碎这四个“绊脚石”
  5. 上海启动5G试用!104页PPT,为你深度解析5G终端的创新和机遇
  6. Hibernate 中的DetachedCriteria。
  7. php网页布局边框,用CSS来设置网页当中的边框
  8. php ip获取邮政编码,php获取指定(访客)IP所有信息(地址、邮政编码、国家、经纬度等)的方法...
  9. 马哥python课堂笔记_马哥-python-课堂笔记12-python核心数据类型及类型显示转换
  10. 为什么世界上近60%的人使用谷歌Chrome浏览器?
  11. MySQL5.5的安装步骤
  12. python爬取网易云音乐评论并进行情感分析_使用python3爬取网易云音乐的评论
  13. 学术英语视听说2听力原文_大学学术英语视听说2-高迎慧
  14. BTA分论坛现场直击|区块链+时下新科技,你了解多少?
  15. kernel更改开机画面
  16. U盘被写保护?我来教你高级格式化
  17. mysql ctrl+y_mysql操作
  18. 网易笔试001(HR之声)
  19. Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operat
  20. xnio-nio解决方法

热门文章

  1. mysql 范式化_MySQL-范式和反范式
  2. tps 交易量_交易处理系统(TPS)
  3. python实现接口_Python | 使用类实现接口
  4. math.pow int_Java Math类static int min(int i1,int i2)与示例
  5. sqldeveloper mysql迁移_通过SQL Developer工具将MySQL数据库内容迁移至Oracle的步骤
  6. 云计算应用迁移_应用迁移策略到云
  7. 如何在python中获取浮点数的十六进制值?
  8. Redis 持久化——AOF
  9. 从JVM入手,聊聊Java的学习和复习!
  10. jQuery 的选择器 元素选择器