websocket简介
HTTP的缺点
只能由client发请求再由server返回请求结果, server是不能主动发请求到client的.
遇到的问题:
需要实时获取取服务端信息的应用时, client需要频繁轮询server,为了拿到最新信息, client一直这样循环下去
server如果一直没有新的消息, client的大多请求都是无效的, 效率低下.
Client:能发能收 Server:能发能收,但是不能主动发
补充:单工、半双工、全双工的区别
websocket的优点
webSocket协议是基于TCP的一种网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
在webscoket协议中, client利用http来建立tcp连接, 建立tcp连接之后, client与server就可以基于tcp连接来愉快的进行通信了.
websocket和HTTP对比
二者之间的联系:
websocket的client与server是利用http的一次request, response来建立连接的.
<pre class="prettyprint hljs-dark"><code class="language-gcode hljs"><div class="hljs-line">请求头
</div><div class="hljs-line">GET /echo HTTP/<span class="hljs-number">1.1</span>
</div><div class="hljs-line">Host:ji<span class="hljs-symbol">ngxu.test.com:8100</span>
</div><div class="hljs-line">Origi<span class="hljs-symbol">n:http://jingxu.test.com:8099</span>
</div><div class="hljs-line">Sec-WebSocket-Exte<span class="hljs-symbol">nsions:permessage-deflate; client_max_window_bits</span>
</div><div class="hljs-line"><span class="hljs-symbol">Sec-WebSocket-Key:rVX0</span>XFeQzA<span class="hljs-number">9</span>QVXXEfj<span class="hljs-name">m0</span>yw==
</div><div class="hljs-line">Sec-WebSocket-Versio<span class="hljs-symbol">n:13</span>
</div><div class="hljs-line">Upgrade:websocket
</div></code></pre>
<pre class="prettyprint hljs-dark"><code class="language-gcode hljs"><div class="hljs-line">响应头
</div><div class="hljs-line">Co<span class="hljs-symbol">nnection:upgrade</span>
</div><div class="hljs-line"><span class="hljs-symbol">Date:Mon, 04</span> Dec <span class="hljs-number">2017</span> <span class="hljs-number">10</span>:<span class="hljs-number">05</span>:<span class="hljs-number">18</span> GMT
</div><div class="hljs-line">Sec-WebSocket-Accept:q<span class="hljs-number">3</span>dUK<span class="hljs-name">g4</span>lRGCqqRhGIvmE<span class="hljs-number">7</span>sH<span class="hljs-number">8</span>Yuc=
</div><div class="hljs-line">Sec-WebSocket-Exte<span class="hljs-symbol">nsions:permessage-deflate;client_max_window_bits=15</span>
</div><div class="hljs-line">Upgrade:websocket
</div></code></pre>
原生websocket的缺点
现在websocket连接已经建立, 由于websocket没有规范消息体的格式, 所以应用需要自己去定义消息体的格式.
比如我要请求发送消息这个接口, 那么我的消息体可以写成:
/send | params=我是消息
这里一个自定义格式, 中坚线之前的是要调用的地址, 中竖线之后是参数.
由于格式是自己定义的, 所以在服务端我也需要自己写代码来解析这个格式.
stomp over websocket
同 HTTP 在 TCP 套接字上添加请求-响应模型层一样,STOMP 在 WebSocket 之上提供了一个基于帧的格式层,用来定义消息语义;stomp协议很多mq都已支持, 比如rabbitmq, activemq. 很多语言也都有stomp协议的解析client库.
<pre class="prettyprint hljs-dark"><code class="language-gcode hljs"><div class="hljs-line">客户端消息
</div><div class="hljs-line">SE<span class="hljs-symbol">ND</span>
</div><div class="hljs-line"><span class="hljs-symbol">destination:/queue/trade</span>
</div><div class="hljs-line"><span class="hljs-symbol">content-type:application/json</span>
</div><div class="hljs-line"><span class="hljs-symbol">content-length:44</span>
</div><div class="hljs-line">{“actio<span class="hljs-symbol">n”:”BUY”,”ticker”:”MMM”,”shares”,44</span>}
</div><div class="hljs-line">服务端消息
</div><div class="hljs-line">MESSAGE
</div><div class="hljs-line">message-id:<span class="hljs-symbol">nxahklf6</span><span class="hljs-number">-1</span>
</div><div class="hljs-line">subscriptio<span class="hljs-symbol">n:sub-1</span>
</div><div class="hljs-line">desti<span class="hljs-symbol">nation:/topic/price.stock.MMM</span>
</div><div class="hljs-line"><span class="hljs-symbol">{“ticker”:”MMM”,”price”:129</span><span class="hljs-number">.45</span>}
</div></code></pre>
使用简介
通信过程
客户端连接api
<pre class="prettyprint hljs-dark"><code class="language-gcode hljs"><div class="hljs-line">var ws = <span class="hljs-symbol">new WebSocket("wss://echo.websocket.org");</span>
</div><div class="hljs-line"><span class="hljs-symbol">ws.onopen = function(evt) { </span>
</div><div class="hljs-line"><span class="hljs-symbol"> console.log("Connection open ..."); </span>
</div><div class="hljs-line"><span class="hljs-symbol"> ws.send("Hello WebSockets!");</span>
</div><div class="hljs-line"><span class="hljs-symbol">};</span>
</div><div class="hljs-line"><span class="hljs-symbol">ws.onmessage = function(evt) {</span>
</div><div class="hljs-line"><span class="hljs-symbol"> console.log( "Received Message: " + evt.data);</span>
</div><div class="hljs-line"><span class="hljs-symbol"> ws.close();</span>
</div><div class="hljs-line"><span class="hljs-symbol">};</span>
</div><div class="hljs-line"><span class="hljs-symbol">ws.onclose = function(evt) {</span>
</div><div class="hljs-line"><span class="hljs-symbol"> console.log("Connection closed.");</span>
</div><div class="hljs-line"><span class="hljs-symbol">}; </span>
</div></code></pre>
服务端api
广播式发送,类似于群聊
<pre class="prettyprint hljs-dark"><code class="language-java hljs"><div class="hljs-line"><span class="hljs-comment">/**</span>
</div><div class="hljs-line"><span class="hljs-comment"> * 广播消息,不指定用户,所有订阅此的用户都能收到消息</span>
</div><div class="hljs-line"><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> shout</span>
</div><div class="hljs-line"><span class="hljs-comment"> */</span>
</div><div class="hljs-line"> <span class="hljs-meta">@MessageMapping</span>(<span class="hljs-string">"/broadcast"</span>)
</div><div class="hljs-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">broadcast</span><span class="hljs-params">(String msg)</span> </span>{
</div><div class="hljs-line"> simpMessageSendingOperations.convertAndSend(<span class="hljs-string">"/topic/shouts"</span>, msg);
</div><div class="hljs-line"> }
</div></code></pre>
点对点发送,类似于个人聊天
<pre class="prettyprint hljs-dark"><code class="language-java hljs"><div class="hljs-line"><span class="hljs-meta">@MessageMapping</span>(<span class="hljs-string">"/single"</span>)
</div><div class="hljs-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">singleUser</span><span class="hljs-params">(String msg, StompHeaderAccessor stompHeaderAccessor)</span> </span>{
</div><div class="hljs-line"> Principal user = stompHeaderAccessor.getUser();
</div><div class="hljs-line"> simpMessageSendingOperations.convertAndSendToUser(user.getName(), <span class="hljs-string">"/queue/shouts"</span>, msg);
</div><div class="hljs-line"> }
</div></code></pre></div></body></html>