第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Netty 教程 Netty 教程 Netty WebSocket 協(xié)議

Netty WebSocket 協(xié)議

1. 前言

上一節(jié),我們主要講解了 Http 協(xié)議,本節(jié)我們來講解 Netty 支持的另外一個(gè) WebSocket 協(xié)議,WebSocket 是 HTML5 開始支持的全雙工協(xié)議。

在真實(shí)的開發(fā)當(dāng)中,其實(shí) WebSocket 使用非常的廣泛,特別是在目前前端技術(shù)越來越完善的情況下,很多應(yīng)用都是基于前端技術(shù)去實(shí)現(xiàn),比如:APP、小程序等主流應(yīng)用,前端的技術(shù)完全可以開發(fā)出類似原生技術(shù)一樣的產(chǎn)品,并且開發(fā)效率上比原生更加的快、用戶體驗(yàn)更好。
這些應(yīng)用涉及通信、聊天、推送等業(yè)務(wù),則可以使用 WebSocket 來實(shí)現(xiàn),因此,WebSocket 已經(jīng)是目前非常主流的瀏覽器和服務(wù)端建立長連接的通信技術(shù)。

WebSocket 協(xié)議架構(gòu)圖如下所示:
圖片描述

2. 學(xué)習(xí)目的

Netty 雖然可以開發(fā)客戶端和服務(wù)端的應(yīng)用,但是 Netty 和 WebSocket 結(jié)合則是另外一個(gè)不同的應(yīng)用方向。

應(yīng)用方向一: 純后端的應(yīng)用,比如:框架、中間件通信等,則完全可以使用 Netty 來開發(fā)客戶端和服務(wù)端,并且雙方通過 TCP 協(xié)議來進(jìn)行通信。

應(yīng)用方向二: 前端(瀏覽器)和服務(wù)端之間通信,并且想實(shí)現(xiàn)類似長連接的效果,那么 WebSocket 和 Netty 則是主流,并且這部分的應(yīng)用場景非常的廣泛和運(yùn)用非常的多。

因此,我們在學(xué)習(xí)完本章內(nèi)容之后,我們就可以掌握這類的需求的開發(fā)(比如:聊天、消息推送),自己可以嘗試去開發(fā)一款小程序在線聊天系統(tǒng)。

當(dāng)真實(shí)的開發(fā)當(dāng)中,也許很多人直接使用 Spring 封裝的 WebSocket 或者其它第三方的框架(比如:netty-socketio)去實(shí)現(xiàn)。本節(jié)我們主要講解原生 Netty 來開發(fā) WebSocket 協(xié)議格式的數(shù)據(jù)請(qǐng)求,畢竟會(huì)用和知道知其所以然還是有區(qū)別的。

3. WebSocket 的 API

創(chuàng)建 WebSocket 對(duì)象,第一個(gè)參數(shù) url, 指定連接的 URL。第二個(gè)參數(shù) protocol 是可選的,指定了可接受的子協(xié)議。

var Socket = new WebSocket(url, [protocol] );

WebSocket 事件

事件 事件處理程序 描述
open Socket.onopen 連接建立時(shí)觸發(fā)
message Socket.onmessage 客戶端接收服務(wù)端數(shù)據(jù)時(shí)觸發(fā)
error Socket.onerror 通信發(fā)生錯(cuò)誤時(shí)觸發(fā)
close Socket.onclose 連接關(guān)閉時(shí)觸發(fā)

4. 環(huán)境搭建

本節(jié),我們主要開發(fā)一個(gè) Demo,主要功能如下:

  1. 前端頁面(html)啟動(dòng)的時(shí)候,連接 WebSocket 服務(wù)端;
  2. 服務(wù)端往前端每隔 5s 推送一條消息。

環(huán)境搭建步驟:

  1. 創(chuàng)建一個(gè) Maven 項(xiàng)目;
  2. 導(dǎo)入 Netty 坐標(biāo)。

實(shí)例:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.6.Final</version>
</dependency>

5. 代碼實(shí)現(xiàn)

5.1. Netty 主啟動(dòng)類

public class MyWebSocketServer {
    public static void main(String[] args) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();

                    //因?yàn)榛趆ttp協(xié)議,使用http的編碼和解碼器
                    pipeline.addLast(new HttpServerCodec());

                    //是以塊方式寫,添加ChunkedWriteHandler處理器
                    pipeline.addLast(new ChunkedWriteHandler());
                    
                    //http數(shù)據(jù)在傳輸過程中是分段, HttpObjectAggregator ,就是可以將多個(gè)段聚合
                    pipeline.addLast(new HttpObjectAggregator(8192));
                    
                    //將 http協(xié)議升級(jí)為 ws協(xié)議 , 保持長連接
                    pipeline.addLast(new WebSocketServerProtocolHandler("/hello2"));
                    
                    //自定義的handler ,處理業(yè)務(wù)邏輯
                    pipeline.addLast(new MyWebSocketHandler());
                }
            });

            //啟動(dòng)服務(wù)器
            ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

代碼說明:

  1. WebSocket 比 TCP 和 Http 協(xié)議都稍微復(fù)雜有點(diǎn),它其實(shí)是 TCP 和 Http 協(xié)議的結(jié)合,首先是連接之前發(fā)送的是 Http 協(xié)議請(qǐng)求,但是新增 Http 所沒有的附加頭信息 Upgrade: WebSocket 表明是一個(gè)申請(qǐng)協(xié)議升級(jí)的 Http 請(qǐng)求。其次,真正建立連接之后,其實(shí)底層是 TCP 協(xié)議長連接;
  2. HttpServerCodec 將請(qǐng)求和應(yīng)答消息解碼為 HTTP 消息;
  3. ChunkedWriteHandler 向客戶端發(fā)送 HTML5 文件;
  4. http 數(shù)據(jù)在傳輸過程中是分段,當(dāng)瀏覽器發(fā)送大量數(shù)據(jù)時(shí),就會(huì)發(fā)出多次 http 請(qǐng)求, HttpObjectAggregator 可以將 HTTP 消息的多個(gè)部分合成一條完整的 HTTP 消息;
  5. WebSocketServerProtocolHandler 定義了 WebSocket 的對(duì)外暴露地址。

5.2 WebSocket 業(yè)務(wù)類

public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
    private SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //1.獲取Channel通道
        final Channel channel=ctx.channel();
        
        //2.創(chuàng)建一個(gè)定時(shí)線程池
        ScheduledExecutorService ses=Executors.newScheduledThreadPool(1);
        //3.一秒鐘之后只需,并且每隔5秒往瀏覽器發(fā)送數(shù)據(jù)
        ses.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                String sendTime=format.format(new Date());
                channel.writeAndFlush(new TextWebSocketFrame("推送時(shí)間=" + sendTime));
            }
        },1,5, TimeUnit.SECONDS);
    }

    //接受瀏覽器消息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

        System.out.println("收到消息 " + msg.text());
    }

    //當(dāng)web客戶端連接后,觸發(fā)方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		
    }

    //當(dāng)web客戶端斷開后,觸發(fā)方法
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

    }
}

代碼說明:

其實(shí) WebSocket 對(duì)于的 Handler 跟我們普通業(yè)務(wù)的 Handler 沒有什么區(qū)別,這里主要使用定時(shí)線程池定時(shí)往瀏覽器推送消息,這個(gè)是傳統(tǒng)的 Http+Ajax 請(qǐng)求無法實(shí)現(xiàn)的逆向推送效果。

5.3. 前端代碼

function WebSocketTest() {
    if ("WebSocket" in window) {
        var ws = new WebSocket("ws://localhost:7000/hello2");
        
        //發(fā)送數(shù)據(jù)
        ws.onopen = function() {
            ws.send("發(fā)送數(shù)據(jù)");
        };

        //接受數(shù)據(jù)
        ws.onmessage = function(evt) {
            var received_msg = evt.data;
            console.log(">>>"+received_msg)
        };

        //監(jiān)聽連接關(guān)閉
        ws.onclose = function() {
            alert("連接已關(guān)閉...");
        };
    } else {
        alert("您的瀏覽器不支持 WebSocket!");
    }
}

5.4 測試效果

瀏覽器控制臺(tái)每隔 5s 鐘就能收到服務(wù)端推送過來的消息,如下圖所示:

圖片描述

6. 小結(jié)

  1. 我們需要了解 WebSocket 的應(yīng)用方向,主要是前端和服務(wù)端建立長連接通信;
  2. 掌握 WebSocket 幾個(gè)事件監(jiān)聽方法,open ()、message ()、error ()、close ();
  3. 掌握 Netty 編寫的服務(wù)端寫法,主要是幾個(gè)類 HttpServerCodec、ChunkedWriteHandler、HttpObjectAggregator、WebSocketServerProtocolHandler,Handler 業(yè)務(wù)跟普通業(yè)務(wù)沒啥區(qū)別。