HTTP 和 WebSocket交换机和路由器的区别别

博客分类:
用socket.io实现WebSocket的一个简单例子
客户端代码:
&html&
&title&&/title&
&script src="../js/socket.io.client.js"&&/script&
&script type="text/javascript"&
function doit() {
var socket = io.connect('http://localhost');
socket.on('news', function (data) {//接收到服务器发送过来的名为'new'的数据
console.log(data.hello);//data为应服务器发送过来的数据。
socket.emit('my new event', { my:'new data' });//向服务器发送数据,实现双向数据传输
socket.on('other', function (data) {//接收另一个名为'other'数据,
console.log(data.hello);
socket.emit('event1', { my:'other data' });
&button id='btn' onclick="doit()"&click me&/button&
&/html&
在chrome,Crtl+Shift+j打开终端,可看到输出结果。
socket.io.client.js可以下载到本地,在&script src=".."&指向本机的js库。
服务器用nodejs实现
代码
var http= require('http'), io= require('socket.io'), express= require('express');
var app = express.createServer(), io = io.listen(app);
app.listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });//监听,一旦客户端连接上,即发送数据,第一个参数'new'为数据名,第二个参数既为数据
socket.on('my other event', function (data) {//捕获客户端发送名为'my other event'的数据
console.log(data.my);
socket.emit('other', { hello: 'other world' });//发送另一个数据
socket.on('evnet1', function (data) {//捕获另外一个数据
console.log(data.my);
});
测试结果,客户端可正常显示
引用world
other world
服务器端显示结果:
引用C:\java\Nodejs&node server2.js
&& info& - socket.io started
&& debug - client authorized
&& info& - handshake authorized
&& debug - setting request GET /socket.io/1/websocket/
&& debug - set heartbeat interval for client
&& debug - client authorized for
&& debug - websocket writing 1::
&& debug - websocket writing 5:::{"name":"news","args":[{"hello":"world"}]}
&& debug - websocket writing 5:::{"name":"other","args":[{"hello":"other world"}
]}
&& debug - emitting heartbeat for client
&& debug - websocket writing 2::
&& debug - set heartbeat timeout for client
&& debug - got heartbeat packet
&& debug - cleared heartbeat timeout for client
&& debug - set heartbeat interval for client
浏览 32018
提示找不到 expressnpm install express另外,有些IO API已经deprecated,改成:var http= require('http'), io= require('socket.io');
var app = http.createServer(), io = io.listen(app);
app.listen(81);这样就可以不必引用express
浏览: 144775 次
如果是數據庫有定時任務,定時更新表的數據。 表中數據變化時,主 ...
在世界的中心呼喚愛 写道提示找不到 expressnpm in ...
提示找不到 express
puts 'invoke m1'
补充,任何类,只要实现to_proc方法,都可以与&结 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'博客分类:
Spring 4.0的一个最大更新是增加了websocket的支持。websocket提供了一个在web应用中的高效、双向的通讯,需要考虑到客户端(浏览器)和服务器之间的高频和低延时消息交换。一般的应用场景有:在线交易、游戏、协作、数据可视化等。
使用websocket需要考虑的浏览器的支持(IE&10不支持),目前主流的浏览器都能很好的支持websocket。
websocket协议中有一些子协议,可以从更高的层次实现编程模型,就像我们使用HTTP而不是TCP一样。这些子协议有STOMP,WAMP等。
本教程只考虑websocket的简单实用,包含Spring对JSR-356的支持及Spring WebSocket API。
1、Java API for WebSocket(JSR-356)
Java API for WebSocket已经是Java EE 7的一部分。它定义了两类endpoit(都是EndPoint类的子类),使用注解标识@ClientEndpoint和@ServerEndpoint。
1.1 Servlet容器扫描初始化
通过Spring初始化一个endpoint,只需配置一个SpringConfigurator在类上的@ServerEndpoint注解上。
import javax.websocket.server.ServerE
import org.springframework.web.socket.server.endpoint.SpringC
@ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class);
public class EchoEndpoint {
private final EchoService echoS
@Autowired
public EchoEndpoint(EchoService echoService) {
this.echoService = echoS
@OnMessage
public void handleMessage(Session session, String message) {
上例假设SpringContextLoaderListener用来加载配置,这是个典型的web应用。Servlet容器将通过扫描@ServerEndpoint和SpringConfigurator初始化一个新的websocket会话。
1.2 Spring 初始化
如果你想使用一个单独的实例而不使用Servlet容器扫描,将EchoEndpoint类声明称一个bean,并增加一个ServerEndpointExporter的bean:
import org.springframework.web.socket.server.endpoint.ServerEndpointE
@Configuration
public class EndpointConfig {
public EchoEndpoint echoEndpoint() {
return new EchoEndpoint(echoService());
public EchoService echoService() {
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
EchoEndpoint 可以通过EndPointRegistration发布:
import org.springframework.web.socket.server.endpoint.ServerEndpointE
import org.springframework.web.socket.server.endpoint.ServerEndpointR
@Configuration
public class EndpointConfig {
public EndpointRegistration echoEndpoint() {
return new EndpointRegistration("/echo", EchoEndpoint.class);
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
本例源码:
2、Spring WebSocket API
Spring WebSocket API提供了SockJS的支持,且有些容器如Jetty 9目前还没有对JSR-356的支持,所以有Spring WebSocket API是必要的。
Spring WebSocket API的核心接口是WebSocketHandler。下面是一个处理文本消息的handler的实现:
import org.springframework.web.socket.adapter.TextWebSocketHandlerA
public class EchoHandler extends TextWebSocketHandlerAdapter {
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
session.sendMessage(message);
WebSocketHandler可以通过WebSocketHttpRequestHandler插入到Spring MVC里:
import org.springframework.web.socket.server.support.WebSocketHttpRequestH
@Configuration
public class WebConfig {
public SimpleUrlHandlerMapping handlerMapping() {
Map&String, Object& urlMap = new HashMap&String, Object&();
urlMap.put("/echo", new WebSocketHttpRequestHandler(new EchoHandler()));
SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
hm.setUrlMap(urlMap);
SockJS服务器端的支持
SockJs是一个脚本框架,它提供类似于websocket的编程模式但是可以适应不同的浏览器(包括不支持websocket的浏览器)。
开启SockJS的支持,声明一个SockJsService,和一个url映射,然后提供一个WebSocketHandler来处理消息。虽然我们是哟个SockJS我们开发的方式是一样的,但是随着浏览器的不同传输的协议可以是Http Streaming,long polling等。
import org.springframework.web.socket.sockjs.SockJsS
@Configuration
public class WebConfig {
public SimpleUrlHandlerMapping handlerMapping() {
SockJsService sockJsService = new DefaultSockJsService(taskScheduler());
Map&String, Object& urlMap = new HashMap&String, Object&();
urlMap.put("/echo/**", new SockJsHttpRequestHandler(sockJsService, new EchoHandler()));
SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
hm.setUrlMap(urlMap);
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setThreadNamePrefix("SockJS-");
return taskS
在我们实际使用中我们会使用WebSocketConfigurer集中注册WebSocket服务:
@Configuration
@EnableWebMvc
@EnableWebSocket//开启websocket
public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoWebSocketHandler(), "/echo"); //提供符合W3C标准的Websocket数据
registry.addHandler(snakeWebSocketHandler(), "/snake");
registry.addHandler(echoWebSocketHandler(), "/sockjs/echo").withSockJS();//提供符合SockJS的数据
registry.addHandler(snakeWebSocketHandler(), "/sockjs/snake").withSockJS();
public WebSocketHandler echoWebSocketHandler() {
return new EchoWebSocketHandler(echoService());
public WebSocketHandler snakeWebSocketHandler() {
return new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class);
public DefaultEchoService echoService() {
return new DefaultEchoService("Did you say \"%s\"?");
// Allow serving HTML files through the default Servlet
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
SockJS客户端代码:
ws = new SockJS(url, undefined, {protocols_whitelist: transports}) ;
//初始化 websocket
ws.onopen = function () {
setConnected(true);
log('Info: connection opened.');
ws.onmessage = function (event) {
log('Received: ' + event.data); //处理服务端返回消息
ws.onclose = function (event) {
setConnected(false);
log('Info: connection closed.');
log(event);
ws.send(message);//向服务端发送消息
程序用maven打成war后用tomcat 8发布查看效果。
本例源码:
新书推荐《JavaEE开发的颠覆者: Spring Boot实战》,涵盖Spring 4.x、Spring MVC 4.x、Spring Boot企业开发实战。
京东地址:
当当地址:
亚马逊地址:
或自己在京东、淘宝、亚马逊、当当、互动出版社搜索自选。
下载次数: 1796
下载次数: 3698
浏览 78553
引用引用引用引用[/u][/u][list][*][list][*][*][list][*][*][*][list][*][*][*][*][list][*][*][*][*][*][list][*][*][*][*][*][*][list][*][*][*][*][*][*][*][list][*][*][*][*][*][*][*][*][list][*][*][*][*][*][*][*][*][*][list][*][*][*][*][*][*][*][*][*][*][list][*][*][*][*][*][*][*][*][*][*][*][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][*][*][*][*][*][*][*][*][*][/list][*][*][*][*][*][*][*][*][/list][*][*][*][*][*][*][*][/list][*][*][*][*][*][*][/list][*][*][*][*][*][/list][*][*][*][*][/list][*][*][*][/list][*][*][/list][*][/list][/list][/list]
浏览: 1138510 次
来自: 合肥
浏览量:49765
浏览量:88164
博主你好。如果groovy的代码保存在数据库里,不是文件里,这 ...
建议博主将源码放在一些不需要注册才可以下载的地方.
jjianwen68 写道使用两个configuration来 ...
P208 代码解释 pinciple -& princi ...
141页 6.1.5 starter pom 上面一行 附录
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'websocket和HTTP使用不同端口可以吗 - CNode技术社区
这家伙很懒,什么个性签名都没有留下。
比如:HTTP监听端口80,websocket想分离到专门的服务器上监听端口6180
浏览器端会存在安全限制吗?
防火墙会阻止掉非常用端口
你可以用80来代理
也就是说websocket一般监听80端口,但感觉HTTP和websocket放到一起出错率会变大
而且有websocket的服务器的负载均衡要用ip_hash策略,用轮询方式负载建立websocket连接后,为什么会需要重新建立连接
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的博客分类:
一、WebSocket不同版本的三种握手方式
WebSocket是HTML5中的新特性,应用也是非常的广泛,特别是用户WEB端与后台服务器的消息通讯,如阿里的WEBWW就是使用的 WebSocket与后端服务器建立长连接进行的通讯。目前WebSocket还处于发展当中,就目前的发展过程而言,WebSocket现在不同的版 本,有三种不同的握手方式:
1、基于Flash的WebSocket通讯,使用场景是IE的多数版本,因为IE的多数版本不都不支持WebSocket协议,以及FF、CHROME等浏览器的低版本,还没有原生的支持WebSocket,可以使用FLASH的WebSocket实现进行通讯:
浏览器请求:
GET /ls HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
服务器回应:
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin:
WebSocket-Location: ws:///ls
如果客户端没有发送Origin请求头,则客户端不需要返回,如果客户端没有发送WebSocket-Protocol请求头,服务端也不需要返回;服务端唯一需要组装返回给客户端做为校验的就是WebSocket-Location请求头,拼装一个websocket请求的地址就可以了。
这种方式,是最老的一种方式,连一个安全Key都没有,服务端也没有对客户的请求做加密性校验。
2、第二种握手方式是带两个安全key请求头的,结果以md5加密,并放在body中返回的方式,参看如下示例:
浏览器请求:
GET /demo HTTP/1.1
Connection: Upgrade
Sec-WebSocket-Key2:
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1
46546xW%0l 1 5
服务器回应:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin:
Sec-WebSocket-Location: ws:///demo
Sec-WebSocket-Protocol: sample
8jKS’y:G*Co,Wxa-
在请求中的“Sec-WebSocket-Key1”, “Sec-WebSocket-Key2”和最后的“^n:ds[4U”都是随机的,服务器端会用这些数据来构造出一个16字节的应答。
把第一个Key中的数字除以第一个Key的空白字符的数量,而第二个Key也是如此。然后把这两个结果与请求最后的8字节字符串连接起来成为一个字符串,服务器应答正文(“8jKS’y:G*Co,Wxa-”)即这个字符串的MD5 sum。
3、第三种是带一个安全key的请求,结果是先以“SHA-1”进行加密,再以base64的加密,结果放在Sec-WebSocket-Accept请求头中返回的方式:
浏览器请求:
GET /ls HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Origin:
Sec-WebSocket-Key: 2SCVXUeP9cTjV+0mWB8J6A==
Sec-WebSocket-Version: 8
服务器回应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: mLDKNeBNWz6T9SxU+o0Fy/HgeSw=
握手的实现,首先要获取到请求头中的Sec-WebSocket-Key的值,再把这一段GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"加到获取到的Sec-WebSocket-Key的值的后面,然后拿这个 字符串做SHA-1 hash计算,然后再把得到的结果通过base64加密,就得到了返回给客户端的Sec-WebSocket-Accept的http响应头的值。
还可以参看我前面专门针对这种协议写的一篇文章:
二、基于Netty实现JAVA类
为了支持以上提到的三种不同版本的websocket握手实现,服务端就需要针对这三种情况进行相应的处理,以下是一段基于netty实现的java代码,一个完整的WebSocketHelper实现:
import java.io.UnsupportedEncodingE
import java.security.MessageD
import java.security.NoSuchAlgorithmE
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.buffer.ChannelB
import org.jboss.netty.handler.codec.http.DefaultHttpR
import org.jboss.netty.handler.codec.http.HttpH
import org.jboss.netty.handler.codec.http.HttpHeaders.N
import org.jboss.netty.handler.codec.http.HttpR
import org.jboss.netty.handler.codec.http.HttpR
import org.jboss.netty.handler.codec.http.HttpResponseS
import org.jboss.netty.handler.codec.http.HttpV
public class WebSocketHelper {
private final static String SEC_WEBSOCKET_KEY
= "Sec-WebSocket-Key";
private final static String SEC_WEBSOCKET_ACCEPT
= "Sec-WebSocket-Accept";
private final static String Sec_WebSocket_Version = "Sec-WebSocket-Version";
public boolean supportWebSocket(HttpRequest req) {
return (HttpHeaders.Values.UPGRADE.equalsIgnoreCase(req.getHeader(HttpHeaders.Names.CONNECTION)) && HttpHeaders.Values.WEBSOCKET.equalsIgnoreCase(req.getHeader(HttpHeaders.Names.UPGRADE)));
public HttpResponse buildWebSocketRes(HttpRequest req) {
String reasonPhrase = "";
boolean isThirdTypeHandshake = Boolean.FALSE;
int websocketVersion = 0;
if (req.getHeader(Sec_WebSocket_Version) != null) {
websocketVersion = Integer.parseInt(req.getHeader(Sec_WebSocket_Version));
if (websocketVersion &= 13
|| (req.containsHeader(Names.SEC_WEBSOCKET_ORIGIN) && req.containsHeader(SEC_WEBSOCKET_KEY))) {
isThirdTypeHandshake = Boolean.TRUE;
if (isThirdTypeHandshake = Boolean.FALSE) {
reasonPhrase = "Switching Protocols";
reasonPhrase = "Web Socket Protocol Handshake";
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, new HttpResponseStatus(101, reasonPhrase));
res.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET);
res.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE);
if (req.containsHeader(Names.SEC_WEBSOCKET_KEY1) && req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {
res.addHeader(Names.SEC_WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
res.addHeader(Names.SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, protocol);
String key1 = req.getHeader(Names.SEC_WEBSOCKET_KEY1);
String key2 = req.getHeader(Names.SEC_WEBSOCKET_KEY2);
int a = (int) (Long.parseLong(getNumeric(key1)) / getSpace(key1).length());
int b = (int) (Long.parseLong(getNumeric(key2)) / getSpace(key2).length());
long c = req.getContent().readLong();
ChannelBuffer input = ChannelBuffers.buffer(16);
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ChannelBuffer output = null;
output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array()));
} catch (NoSuchAlgorithmException e) {
res.setContent(output);
} else if (isThirdTypeHandshake = Boolean.FALSE) {
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, protocol);
res.addHeader(SEC_WEBSOCKET_ACCEPT, getSecWebSocketAccept(req));
if (req.getHeader(Names.ORIGIN) != null) {
res.addHeader(Names.WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
res.addHeader(Names.WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.WEBSOCKET_PROTOCOL, protocol);
private String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + req.getUri();
private String getSecWebSocketAccept(HttpRequest req) {
String guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
String key = "";
key = req.getHeader(SEC_WEBSOCKET_KEY);
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(key.getBytes("iso-8859-1"), 0, key.length());
byte[] sha1Hash = md.digest();
key = base64Encode(sha1Hash);
} catch (NoSuchAlgorithmException e) {
} catch (UnsupportedEncodingException e) {
String base64Encode(byte[] input) {
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
String base64 = encoder.encode(input);
return base64;
private String getNumeric(String str) {
return str.replaceAll("\\D", "");
private String getSpace(String str) {
return str.replaceAll("\\S", "");
三、注意事项
不同版本的WebSocket标准,编码和解码的方式还有所不同,在第一种和第二种WebSocket协议标准中,使用Netty自带的Encoder和Decoder即可:
org.jboss.netty.handler.codec.http.websocket.WebSocketFrameEncoder org.jboss.netty.handler.codec.http.websocket.WebSocketFrameDecoder
而如果要支持第三种实现标准,Netty目前官方还不支持,可以到github中找到实现的Encoder及Decoder:
不过,它的实现有一点问题,就是没有处理客户端主动发起的WebSocket请求断开,既客户端主动发起opcode为8的请求,不过它还是有预留的,找到这个类:
Hybi10WebSocketFrameDecoder
的包含这以下内容的行:
} else if (this.opcode == OPCODE_CLOSE) {
在其中插入:
return new DefaultWebSocketFrame(0x08, frame);
然后在你的实现子类中增加如下的代码判断即可:
if (frame.getType() == 0x08) {
浏览: 345466 次
来自: 广州
推荐一款轻量开源的支付宝组件:https://github.c ...
太好了,非常有用,谢谢分享~
http://www.atool.org/json2javab ...
这样只要是手机登录了微信的用户。扫描二维码后都可以登录进入网站 ...
好文章,收藏~\(≧▽≦)/~啦啦啦
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'WebSocket与http的区别,以及它的原理--
一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)
首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解
(没有画图工具)
src="/ec133b0e6d7e6d0e194b4c_b.jpg"
data-rawwidth="374" data-rawheight="133" class="content_image"
width="374"&有交集,但是并不是全部。
有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。
通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=
再简单来说,层级不一样。
二、Websocket是什么样的协议,具体有什么优点
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request
一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response ,
在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。
教练,你BB了这么多,跟Websocket有什么关系呢?
_(:з」∠)_好吧,我正准备说Websocket呢。。
首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。
在握手阶段是一样的
-------以下涉及专业技术内容,不想看的可以跳过lol:,或者只看加黑内容--------
首先我们来看个典型的Websocket握手(借用Wikipedia的。。)
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。
我会顺便讲解下作用。
Upgrade: websocket
Connection: Upgrade
这个就是Websocket的核心了,告诉Apache、Nginx等服务器:注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
首先,Sec-WebSocket-Key 是一个Base64
encode的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。
然后,Sec_WebSocket-Protocol
是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~
最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket
Draft(协议版本),在最初的时候,Websocket协议还在 Draft
阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~
脱水:服务员,我要的是13岁的噢→_→
然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocket
Connection: Upgrade
依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的
Sec-WebSocket-Key。服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。
后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。
至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。
具体的协议就不在这阐述了。
------------------技术解析部分完毕------------------
src="/afe119b52eedabc2dfa9661_b.jpg"
data-rawwidth="161" data-rawheight="187" class="content_image"
width="161"&你TMD又BBB了这么久,那到底Websocket有什么鬼用,http long
poll,或者ajax轮询不都可以实现实时信息传递么。你TMD又BBB了这么久,那到底Websocket有什么鬼用,http
long poll,或者ajax轮询不都可以实现实时信息传递么。
src="/edb1ed826e264_b.jpg"
data-rawwidth="176" data-rawheight="193" class="content_image"
width="176"&
好好好,年轻人,那我们来讲一讲Websocket有什么用。
来给你吃点胡(苏)萝(丹)卜(红)
src="/31ddf0cfbeecef21568d85ca60b5f1ff_b.jpg"
data-rawwidth="53" data-rawheight="65" class="content_image"
width="53"&三、Websocket的作用
在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。
首先是 ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) ---- loop
long poll 其实原理跟 ajax轮询
差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。
说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以ajax轮询 和long poll 都有可能发生这种情况。
客户端:啦啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:。。。。好吧,啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:&img
src="/7c0cf075c7ee4cc6cf52f4572a4c1c10_b.jpg"
data-rawwidth="143" data-rawheight="50" class="content_image"
width="143"&
然后服务端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我错了。。这又是梗。。)
--------------------------
言归正传,我们来说Websocket吧
通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。
一种需要更快的速度,一种需要更多的'电话'。这两种都会导致'电话'的需求越来越高。
哦对了,忘记说了HTTP还是一个状态协议。
通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。
所以在这种情况下出现了,Websocket出现了。
他解决了HTTP的这几个难题。
首先,被动性,当服务器完成协议升级后(HTTP-&Websocket),服务端就可以主动推送信息给客户端啦。
所以上面的情景可以做如下修改。
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
服务端:笑死我了哈哈哈哈哈哈哈
就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你)
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。
那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。
简单地说,我们有一个非常快速的接线员(Nginx),他负责把问题转交给相应的客服(Handler)。
本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。
Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。
同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输identity
info(鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。
但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity
info的信息。
同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了
--------------------
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是:不能
但是可以通过上面说的 long poll 和 ajax 轮询来 模拟出类似的效果
----come from ovear
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 荣耀9和v9 区别 的文章

 

随机推荐