日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


看完讓你徹底搞懂Websocket原理,附通過netty完成Websocket

 

 

(一)websocket協議概述

假設我們要實現一個WEB版的聊天室可以采用哪些方案?

1.Ajax輪詢去服務器取消息

客戶端按照某個時間間隔不斷地向服務端發送請求,請求服務端的最新數據然后更新客戶端顯示。這種方式實際上浪費了大量流量并且對服務端造成了很大壓力。

2.Flash XMLSocket

在 html 頁面中內嵌入一個使用了 XMLSocket 類的 Flash 程序。JAVAScript 通過調用此Flash程序提供的套接口接口與服務器端的套接口進行通信。JavaScript 在收到服務器端以 XML 格式傳送的信

息后可以很容易地控制 HTML 頁面的內容顯示。

  • 以上方案的弊端

Ajax 輪詢:

  1. Http為半雙工協議,也就是說同一時刻,只有一個方向的數據傳送。
  2. Http消息冗長,包含請求行、請求頭、請求體。占用很多的帶寬和服務器資源。
  3. 空輪詢問題。
  4. 政府項目直接用ajax,別搞那么復雜,它不存在并發問題。

Flash XMLSocket

  1. 客戶端必須安裝 Flash 播放器,而且瀏覽器需要授權。
  2. 因為 XMLSocket 沒有 HTTP 隧道功能,XMLSocket 類不能自動穿過防火墻。
  3. 因為是使用套接口,需要設置一個通信端口,防火墻、代理服務器也可能對非 HTTP 通道端口進行限制。

為了解決上述弊端,Html5定義了WebSocket協義能更好的節省服務器資源和寬帶達到實時通信的目的。

  • webSocket 協議簡介

webSocket 是html5 開始提供的一種瀏覽器與服務器間進行全雙工二進制通信協議,其基于TCP雙向全雙工作進行消息傳遞,同一時刻即可以發又可以接收消息,相比Http的半雙工協議性能有很大的提升。

  • webSocket特點如下:
  1. 單一TCP長連接,采用全雙工通信模式。
  2. 對代理、防火墻透明,80端口必須打開吧。
  3. 無頭部信息、消息更精簡。
  4. 通過ping/pong 來保活。
  5. 服務器可以主動推送消息給客戶端,不在需要客戶輪詢。
  • WebSocket 協議報文格式

任何應用協議都有其特有的報文格式,比如Http協議通過 空格 換行組成其報文。如http 協議不同在于WebSocket屬于二進制協議,通過規范進二進位來組成其報文。

 

看完讓你徹底搞懂Websocket原理,附通過netty完成Websocket

 

 

  • 報文說明:

FIN

標識是否為此消息的最后一個數據包,占 1 bit

RSV1, RSV2, RSV3

用于擴展協議,一般為0,各占1bit

Opcode

數據包類型(frame type),占4bits

0x0:標識一個中間數據包

0x1:標識一個text類型數據包

0x2:標識一個binary類型數據包

0x3-7:保留

0x8:標識一個斷開連接類型數據包

0x9:標識一個ping類型數據包

0xA:表示一個pong類型數據包

0xB-F:保留

MASK

占1bits

用于標識PayloadData是否經過掩碼處理。如果是1,Masking-key域的數據即是掩碼密鑰,用于解碼

PayloadData。客戶端發出的數據幀需要進行掩碼處理,所以此位是1。

Payload length

Payload data的長度,占7bits,7+16bits,7+64bits:

如果其值在0-125,則是payload的真實長度。如果值是126,則后面2個字節形成的16bits無符號整型數的值是payload的真實長度。注意,網絡字節序,需要轉換。如果值是127,則后面8個字節形成的64bits無符號整型數的值是payload的真實長度。注意,網絡字節序,需要轉換。

Payload data

應用層數據

  • WebSocket 在瀏覽當中的使用

Http 連接與webSocket 連接建立示意圖

 

看完讓你徹底搞懂Websocket原理,附通過netty完成Websocket

 

 

通過javaScript 中的API可以直接操作WebSocket 對象

var ws = new WebSocket(“ws://localhost:8080”);
ws.onopen = function()// 建?成功之后觸發的事件
{
 console.log(“打開連接”);
 ws.send("ddd"); // 發送消息
};
ws.onmessage = function(evt) { // 接收服務器消息
 console.log(evt.data);
};
ws.onclose = function(evt) {
 console.log(“WebSocketClosed!”); // 關閉連接
};
ws.onerror = function(evt) {
 console.log(“WebSocketError!”); // 連接異常
};

1.申請一個WebSocket對象,并傳入WebSocket地址信息,這時client會通過Http先發起握手請求

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket //告訴服務端需要將通信協議升級到websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== //瀏覽器base64加密的密鑰,server端收到后需
要提取Sec-WebSocket-Key 信息,然后加密。
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat //表?客?端請求提供的可供選擇的?協議
Sec-WebSocket-Version: 13 //版本標識

2.服務端響應、并建立連接

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: SIEylb7zRYJAEgiqJXaOW3V+ZWQ=

3.握手成功促發客戶端 onOpen 事件

  • 連接狀態查看

通過ws.readyState 可查看當前連接狀態可選值

  1. CONNECTING (0):表示還沒建立連接。
  2. OPEN (1): 已經建立連接,可以進行通訊。
  3. CLOSING (2):通過關閉握手,正在關閉連接。
  4. CLOSED (3):連接已經關閉或無法打開。

(二)netty實現websocket演示

源碼:https://github.com/limingIOS/netFuture/tree/master/源碼/『互聯網架構』軟件架構-io與nio線程模型reactor模型(上)(53)/nio

源碼:websocket

WebsocketServer.java

package com.dig8.websocket;

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.EventLoopGroup;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.nio.NioServerSocketChannel;

import io.netty.handler.logging.LogLevel;

import io.netty.handler.logging.LoggingHandler;

public class WebsocketServer {

public static void main(String[] args) throws InterruptedException {

EventLoopGroup bossGroup = new NioEventLoopGroup();

EventLoopGroup workerGroup = new NioEventLoopGroup();

try{

ServerBootstrap serverBootstrap = new ServerBootstrap();

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

.handler(new LoggingHandler(LogLevel.INFO))

.childHandler(new WebSocketChannelInitializer());

ChannelFuture channelFuture = serverBootstrap.bind(8989).sync();

channelFuture.channel().closeFuture().sync();

}finally{

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

}

WebSocketChannelInitializer.java

package com.dig8.websocket;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelPipeline;

import io.netty.channel.socket.SocketChannel;

import io.netty.handler.codec.http.HttpObjectAggregator;

import io.netty.handler.codec.http.HttpServerCodec;

import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {

@Override

protected void initChannel(SocketChannel ch) throws Exception {

ChannelPipeline pipeline = ch.pipeline();

//HttpServerCodec: 針對http協議進行編解碼

pipeline.addLast("httpServerCodec", new HttpServerCodec());

//ChunkedWriteHandler分塊寫處理,文件過大會將內存撐爆

pipeline.addLast("chunkedWriteHandler", new ChunkedWriteHandler());

/**

* 作用是將一個Http的消息組裝成一個完成的HttpRequest或者HttpResponse,那么具體的是什么

* 取決于是請求還是響應, 該Handler必須放在HttpServerCodec后的后面

*/

pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(8192));

//用于處理websocket, /ws為訪問websocket時的uri

pipeline.addLast("webSocketServerProtocolHandler", new WebSocketServerProtocolHandler("/ws"));

pipeline.addLast("myWebSocketHandler", new WebSocketHandler());

}

}

WebSocketHandler.java

package com.dig8.websocket;

import io.netty.channel.Channel;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.SimpleChannelInboundHandler;

import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.Date;

public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

@Override

protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

Channel channel = ctx.channel();

System.out.println(channel.remoteAddress() + ": " + msg.text());

ctx.channel().writeAndFlush(new TextWebSocketFrame("來自服務端: " + new Date().toString()));

}

@Override

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

System.out.println("ChannelId" + ctx.channel().id().asLongText());

}

@Override

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

System.out.println("用戶下線: " + ctx.channel().id().asLongText());

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

ctx.channel().close();

}

}

test.html

<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Socket</title>
 <script type="text/javascript">
 var websocket;
 //如果瀏覽器支持WebSocket
 if(window.WebSocket){
 websocket = new WebSocket("ws://localhost:8989/ws"); //獲得WebSocket對象
 //當有消息過來的時候觸發
 websocket.onmessage = function(event){
 var respMessage = document.getElementById("respMessage");
 respMessage.value = respMessage.value + "n" + event.data;
 }
 //連接關閉的時候觸發
 websocket.onclose = function(event){
 var respMessage = document.getElementById("respMessage");
 respMessage.value = respMessage.value + "n斷開連接";
 }
 //連接打開的時候觸發
 websocket.onopen = function(event){
 var respMessage = document.getElementById("respMessage");
 respMessage.value = "建立連接";
 }
 }else{
 alert("瀏覽器不支持WebSocket");
 }
 function sendMsg(msg) { //發送消息
 if(window.WebSocket){
 if(websocket.readyState == WebSocket.OPEN) { //如果WebSocket是打開狀態
 websocket.send(msg); //send()發送消息
 }
 }else{
 return;
 }
 }
 </script>
</head>
<body>
<form onsubmit="return false">
 <textarea style="width: 300px; height: 200px;" name="message"></textarea>
 <input type="button" onclick="sendMsg(this.form.message.value)" value="發送"><br>
 <h3>信息</h3>
 <textarea style="width: 300px; height: 200px;" id="respMessage"></textarea>
 <input type="button" value="清空" onclick="javascript:document.getElementById('respMessage').value = ''">
</form>
</body>
</html>

 

看完讓你徹底搞懂Websocket原理,附通過netty完成Websocket

 

 

看完讓你徹底搞懂Websocket原理,附通過netty完成Websocket

 

 

PS:netty的實現http和websocket基本也就說到這里,具體netty實現RPC這塊我沒演示,我感覺沒必要成熟的框架都是基于netty實現的自己在現實個RPC真沒必要,如果想看netty實現RPC直接看dubbo源碼就可以了。

分享到:
標簽:Websocket
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定