听说小米今天破发了。作为一个伪米粉,我还是比较谈定的,如果你的身边有一个人时长提醒你--苹果干到小米现在的位置需要50年,小米只需要10几年为什么;小米负债千亿人民币...等等谣言。说了这么多,小米依旧是小米,我依旧是哪个普普通通的屌丝程序员。
事件起因:
我在刚开始接触到项目的时候,看到一位同事为了保证本地状态和远端的状态,是用http进行轮询的,就像下面的代码一样:
{
//代码都是临时手写的 可能有不完善的见谅啊
let xmlhttp;
let isFishish = false;
let time = setInterval(()=>{
if(isFishish){
clearInterval(time)
}else{
getHttpRequest();
}
},3000)
function getHttpRequest(){
xmlhttp=null;
if(window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}else if (window.ActiveXObject)
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;
xmlhttp.open("GET",url,true);
xmlhttp.send(null);
}
else
{
alert("Your browser does not support XMLHTTP.");
}
}
function state_Change(){
if (xmlhttp.readyState==4)
{
if (xmlhttp.status==200)
{// 200 = OK
// ...our code here...
} else {
alert("Problem retrieving XML data");
}
}
}
}
这种轮询的方式有好有坏,能够初步的达到用户的需求,但是用户的数据改变却又不能即使的反馈给用户。算了就这样说好像没什么可塑性,就直接用一个生活小实例来描述吧。
- http请求
client:办公室有没有吃的?
server:没有
client:办公室还没有吃的?
server:没有
client:现在有吃的没?
server:没有 - socket请求:
client: 我们来建立socket连接吧,如果你有累点重点的活儿就告诉我
server:求之不得,连接好了
client:有活儿就立马告诉我
server:好的
server:帮我把这数据用Excel表格列出来
client:好的,弄好了
server:谢谢
从上面的例子上面就可以看出socket其实是可以,由服务端发起主动想客户端发送数据的。
介绍一下socket:
前面说了这么多大体都提及了socket,但是具体的socket是什么?有什么优点?基本都介绍的模棱两可。现在来系统的介绍一下
- 介绍一下socket
WebSocket是为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接, - socket的优点在哪儿:
以前我们实现推送技术,用的都是轮询,在特点的时间间隔有浏览器自动发出请求,将服务器的消息主动的拉回来,在这种情况下,我们需要不断的向服务器 发送请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。会占用大量的带宽和服务器资源。
WebSocket API最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。在建立连接之后,服务器可以主动传送数据给客户端。
此外,服务器与客户端之间交换的标头信息很小。
WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;
此后服务端与客户端通过此TCP连接进行实时通信。
我是这样使用socket的
关于socket的使用,我是直接用最基础的源码来写的,虽然最后知道了js里面有一个常用的库,但是想想呢?既然是写文章就直接用最基础的东西更能说明问题。
{
initWebSocket(){ //初始化weosocket
//ws地址
const wsuri = process.env.WS_API + "/websocket/threadsocket";
this.websock = new WebSocket(wsuri);
this.websock.onmessage = this.websocketonmessage
this.websock.onerror = this.websocketerror
this.websock.onopen = this.websocketonopen
this.websock.onclose = this.websocketclose
},
websocketonmessage(e){ //数据接收
const redata = JSON.parse(e.data);
console.log(redata.value);
},
websocketsend(data){//数据发送
this.websock.send(data);
},
websocketclose(e){ //关闭
console.log("connection closed (" + e.code + ")");
}
}
当然,我在这里使用的是vue,这套代码,自己的项目也在使用,是可以使用的。我在这里呢?主要来谈一下websocket的四个方法:
- readyState: 返回实例对象的当前状态,一共有下面四种:
CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
- onopen:用于指定连接成功后的回调函数
当然我也看到很多人这么来写:
websock.addEventListener('open', function (event) {
// dosomethings...
});
- onerror: 用于指定报错时的回调函数
- onmessage: 用于指定收到服务器数据后的回调函数
- onclose: 用于指定连接关闭后的回调函数
- send: 发送socket消息
最后再聊一块钱的
当然,我在开发的时候遇到很常见的一个小问题,那就是socket容易断开。我最后这一块钱就想由断线重连谈起。
我在这里首先来介绍一下前面提到的一个回调onclose
,这个如果存在连接中断的情况会调用该回调,告知客户端。首先看一下参数:
由上面的图解知道,close会有三个参数:
code
、reason
、wasClean
- code:返回一个 unsigned short 类型的数字, 表示服务端发送的关闭码, 以下为已分配的状态码.
状态码 | 名称 | 描述 |
---|---|---|
0–999 |
保留段, 未使用. |
|
1000 |
CLOSE_NORMAL |
正常关闭; 无论为何目的而创建, 该链接都已成功完成任务. |
1001 |
CLOSE_GOING_AWAY |
终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开. |
1002 |
CLOSE_PROTOCOL_ERROR |
由于协议错误而中断连接. |
1003 |
CLOSE_UNSUPPORTED |
由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据). |
1004 |
<wbr> | 保留. <wbr>其意义可能会在未来定义. |
1005 |
CLOSE_NO_STATUS |
保留. <wbr> 表示没有收到预期的状态码. |
1006 |
CLOSE_ABNORMAL |
保留. <wbr>用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧). |
1007 |
Unsupported Data | 由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据). |
1008 |
Policy Violation | 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景. |
1009 |
CLOSE_TOO_LARGE |
由于收到过大的数据帧而断开连接. |
1010 |
Missing Extension | 客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接. |
1011 |
Internal Error | 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接. |
1012 |
Service Restart | 服务器由于重启而断开连接. [Ref] |
1013 |
Try Again Later | 服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接. [Ref] |
1014 |
<wbr> | 由 WebSocket 标准保留以便未来使用. |
1015 |
TLS Handshake | 保留. <wbr>表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书). |
1016 –1999
|
<wbr> | 由 WebSocket 标准保留以便未来使用. |
2000 –2999
|
<wbr> | 由 WebSocket 拓展保留使用. |
3000 –3999
|
<wbr> | 可以由库或框架使用. <wbr>不应由应用使用. 可以在 IANA 注册, 先到先得. |
4000 –4999
|
<wbr> | 可以由应用使用. |
- reson:返回一个
DOMString
用以表示服务器关闭连接的原因. 这是由服务器和子协议决定的. - wasClean: 返回一个 Boolean用以表示连接是否完全关闭.
由上面的基础我们就可以在onclose
回调里面做重连代码,我是这样写的
{
onclose(e){
if(!Object,is(e.code,1000)){
if(!e.wasClean) {
this.websock.close()
}
setTimeout(()=>{
initWebSocket();
},4000)
}
}
}
我这样写呢?暂时也没有发现什么错误,但是也不一定是全正确的。如果诸位看官在使用的时候有任何瑕疵请立即告诉我,我如果在使用中有任何不舒服的,我也会及时更新的。谢谢呢,您咧!!
说在最后
最近老是9点半左右下班,大清早旁边的工地又不停的在吵,搅的人无神无主、五雷轰顶...哇啊啊啊,算了 或许这就是生命吧。反正一切的一切都是在炫耀自己懒罢了。最近呢?也准备和大学室友写一个项目,其中包含前端、后端、Android端。如果有看官希望一起开发、或者有兴趣的话,请联系我。大家一起边开发边学习边成长。好了,午时已到,准备睡觉,嗯 洗澡去了
网友评论