什么是socket?什么是websocket?两者有什么区别?
HTML5规范在传统的web交互基础上为我们带来了众多的新特性,随着web技术被⼴泛⽤于web APP的开发,这些新特性得以推⼴和使⽤,⽽websocket作为⼀种新的web通信技术具有巨⼤意义。
什么是socket?什么是websocket?两者有什么区别?websocket是仅仅将socket的概念移植到浏览器中的实现吗?
我们知道,在⽹络中的两个应⽤程序(进程)需要全双⼯相互通信(全双⼯即双⽅可同时向对⽅发送消息),需要⽤到的就是socket,它能够提供端对端通信,对于程序员来讲,他只需要在某个应⽤程序的⼀端(暂且称之为客户端)创建⼀个socket实例并且提供它所要连接⼀端(暂且称之为服务端)的IP地址和端⼝,⽽另外⼀端(服务端)创建另⼀个socket并绑定本地端⼝进⾏监听,然后客户端进⾏连接服务端,服务端接受连接之后双⽅建⽴了⼀个端对端的TCP连接,在该连接上就可以双向通讯了,⽽且⼀旦建⽴这个连接之后,通信双⽅就没有客户端服务端之分了,提供的就是端对端通信了。我们可以采取这种⽅式构建⼀个桌⾯版的im程序,让不同主机上的⽤户发送消息。从本质上来说,socket并不是⼀个新的协议,它只是为了便于程序员进⾏⽹络编程⽽对tcp/ip协议族通信机制的⼀种封装。
websocket是html5规范中的⼀个部分,它借鉴了socket这种思想,为web应⽤程序客户端和服务端之间(注意是客户端服务端)提供了⼀种全双⼯通信机制。同时,它⼜是⼀种新的应⽤层协议,websocket
协议是为了提供web应⽤程序和服务端全双⼯通信⽽专门制定的⼀种应⽤层协议,通常它表⽰为:ws:///?encoding=text HTTP/1.1,可以看到除了前⾯的协议名和http不同之外,它的表⽰地址就是传统的url地址。
可以看到,websocket并不是简单地将socket这⼀概念在浏览器环境中的移植,本⽂最后也会通过⼀个⼩的demo来进⼀步讲述socket和websocket在使⽤上的区别。
websocket的通信原理和机制
既然是基于浏览器端的web技术,那么它的通信肯定少不了http,websocket本⾝虽然也是⼀种新的应⽤层协议,但是它也不能够脱离http⽽单独存在。具体来讲,我们在客户端构建⼀个websocket实例,并且为它绑定⼀个需要连接到的服务器地址,当客户端连接服务端的时候,会向服务端发送⼀个类似下⾯的http报⽂
可以看到,这是⼀个http get请求报⽂,注意该报⽂中有⼀个upgrade⾸部,它的作⽤是告诉服务端需要将通信协议切换到websocket,如果服务端⽀持websocket协议,那么它就会将⾃⼰的通信协议切换到websocket,同时发给客户端类似于以下的⼀个响应报⽂头
返回的状态码为101,表⽰同意客户端协议转换请求,并将它转换为websocket协议。以上过程都是利⽤http通信完成的,称之为websocket协议握⼿(websocket Protocol handshake),进过这握⼿之后,客户端和服务端就建⽴了websocket连接,以后的通信⾛的都是websocket协议了。所以总结为websocket握⼿需要借助于http协议,建⽴连接后通信过程使⽤websocket协议。同时需要了解的是,该websocket连接还是基于我们刚才发起http连接的那个TCP连接。⼀旦建⽴连接之后,我们就可以进⾏数据传输了,websocket提供两种数据传输:⽂本数据和⼆进制数据。
基于以上分析,我们可以看到,websocket能够提供低延迟,⾼性能的客户端与服务端的双向数据通信。它颠覆了之前web开发的请求处理响应模式,并且提供了⼀种真正意义上的客户端请求,服务器推送数据的模式,特别适合实时数据交互应⽤开发。
在websocket之前,我们在web上要得到实时数据交互都采⽤了哪些⽅式?
1)定期轮询的⽅式:
客户端按照某个时间间隔不断地向服务端发送请求,请求服务端的最新数据然后更新客户端显⽰。这种⽅式实际上浪费了⼤量流量并且对服务端造成了很⼤压⼒。
2)comet技术
comet并不是⼀种新的通信技术,它是在客户端请求服务端这个模式上的⼀种hack技术,通常来讲,它主要分为以下两种做法
(1)基于长轮询的服务端推送技术
具体来讲,就是客户端⾸先给服务端发送⼀个请求,服务端收到该请求之后如果数据没有更新则并不⽴即返回,服务端阻塞请求的返回,直到数据发⽣了更新或者发⽣了连接超时,服务端返回数据之后客户端再次发送同样的请求,如下所⽰:
2)基于流式数据传输的长连接
通常的做法是在页⾯中嵌⼊⼀个隐藏的iframe,然后让这个iframe的src属性指向我们请求的⼀个服务端地址,并且为了数据更新,我们将页⾯上数据更新操作封装为⼀个js函数,将函数名当做参数传递到这个地址当中,
服务端收到请求后解析地址取出参数(客户端js函数调⽤名),每当有数据更新的时候,返回对客户端函数的调⽤,并且将要跟新的数据以js函数的参数填⼊到返回内容当中,例如返回“<script
type="text/javascript">update("data")</script>”这样⼀个字符串,意味着以data为参数调⽤客户端update函数进⾏客户端view更新。基本模型如下所⽰:
可以看到comet技术是针对客户端请求服务器响应模型⽽模拟出的⼀个服务端推送数据实时更新技术。⽽且由于浏览器兼容性不能够⼴泛应⽤。
可以看到comet技术是针对客户端请求服务器响应模型⽽模拟出的⼀个服务端推送数据实时更新技术。⽽且由于浏览器兼容性不能够⼴泛应⽤。
当然并不是说这些技术没有⽤,就算websocket已经作为规范被提出并实现,但是对于⽼式浏览器,我们依然需要将它降级为以上⽅式来实现实时交互和服务端数据推送。
到此为⽌,我们明⽩了websocket的原理,下⾯通过⼀个简单的聊天应⽤来再次加深下对websocket的理解。
该应⽤需求很简单,就是在web选项卡中打开两个⽹页,模拟两个web客户端实现聊天功能。
⾸先是客户端如下:
client.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin: 0; padding: 0;
} .message{ width: 60%; margin: 0 10px; display: inline-block; text-align: center; height: 40px; line-height: 40px; font-size: 20px; border-radius: 5px; border: 1px solid #B3D33F; } .form{ width:100%; position: fixed; bottom: 300px; left: 0;
} .connect{ height: 40px; vertical-align: top;
/* padding: 0; */ width: 80px; font-size: 20px; border-radius: 5px; border: none; background: #B3D33F; color: #fff;
}
</style>
</head>
<body>
<ul id="content"></ul>
<form class="form">
<input type="text" placeholder="请输⼊发送的消息" class="message" id="message"/>
<input type="button" value="发送" id="send" class="connect"/>
<input type="button" value="连接" id="connect" class="connect"/>
</form>
<script></script>
</body>
</html>
客户端js代码
var ElementById('content');
var ElementById('connect');
var ElementById('send');
var ElementById('message');
var ws=null;
ws=new WebSocket('ws://localhost:5000');
oUl.innerHTML+="<li>客户端已连接</li>";
}
oUl.innerHTML+="<li>"+evt.data+"</li>";
}
oUl.innerHTML+="<li>客户端已断开连接</li>";
};
oUl.innerHTML+="<li>"+evt.data+"</li>";
};
};
if(ws){
ws.send(oInput.value);
}
}
这⾥使⽤的是w3c规范中关于HTML5 websocket API的原⽣API,这些api很简单,就是利⽤new WebSocket创建⼀个指定连接服务端地址的ws实例,然后为该实例注册onopen(连接服务端),onmessage(接受服务端数据),onclose(关闭连接)以及ws.send(建⽴连接后)发送请求。上⾯说了那么多,事实上可以看到html5 websocket API本⾝是很简单的⼀个对象和它的⼏个⽅法⽽已。
服务端采⽤nodejs,这⾥需要基于⼀个nodejs-websocket的nodejs服务端的库,它是⼀个轻量级的nodejs websocket server端的实现,实际上也是使⽤nodejs提供的net模块写成的。
server.js
var app=require('http').createServer(handler);
var ws=require('nodejs-websocket');
var fs=require('fs');
app.listen(80);
function handler(req,res){
if(err){
res.writeHead(500);
d('error ');
}
res.writeHead(200);
});
}
var ateServer(function(conn){
console.log('new conneciton');
<("text",function(str){
broadcast(server,str);
});
<("close",function(code,reason){
console.log('connection closed');
})
}).listen(5000);
function broadcast(server, msg) {
conn.sendText(msg);
})
}
⾸先利⽤http模块监听⽤户的http请求并显⽰client.html界⾯,然后创建⼀个websocket服务端等待⽤户连接,在接收到⽤户发送来的数据之后将它⼴播到所有连接到的客户端。
下⾯我们打开两个浏览器选项卡模拟两个客户端进⾏连接,
客户端⼀连接:
请求响应报⽂如下:
可以看到这次握⼿和我们之前讲的如出⼀辙,
客户端⼆的连接过程和1是⼀样的,这⾥为了查看我们使⽤ff浏览器,两个客户端的连接情况如下:
发送消息情况如下:
update是什么可以看到,双⽅发送的消息被服务端⼴播给了每个和⾃⼰连接的客户端。
从以上我们可以看到,要想做⼀个点对点的im应⽤,websocket采取的⽅式是让所有客户端连接服务端,服务器将不同客户端发送给⾃⼰的消息进⾏转发或者⼴播,⽽对于原始的socket,只要两端建⽴连接之后,就可以发送端对端的数据,不需要经过第三⽅的转发,这也是websocket不同于socket的⼀个重要特点。
最后,本⽂为了说明html5规范中的websocket在客户端采⽤了原⽣的API,实际开发中,有⽐较著名的两个库socket.io和sockjs,它们都对原始的API做了进⼀步封装,提供了更多功能,都分为客户端和服务端的实现,实际应⽤中,可以选择使⽤。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论