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

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

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

  • 前言:作為一個剛踏入職場的實習生,我很幸運參加了某個政府項目,并且在項目中負責一個核心模塊功能的開發,而不是從頭到尾對數據庫的crud。雖然我一直心里抱怨我的工作范圍根本就不是實習生干的活,因為沒有前輩帶我、入職就開始改bug。但在這樣的環境下我卻學到了很多東西,即便老板有壓榨我的嫌疑,卻給了我如此好的歷練機會(但工資方面真的很虧QAQ),畢竟實習過后跳槽簡歷上還有亮點。
  • 背景:在不同的網絡環境、不同的開發語言組成的閉環系統中,多個模塊之間要實時獲取硬件設備的狀態,并以xml報文的格式相互傳遞。在必要的時候解析這個報文獲取其中的關鍵信息完成相應的動作,最后直觀地把信息顯示給前端用戶。如此一來就是涉及到了跨終端通信,并且有的功能模塊既要充當客戶端分發指令,還要作為客戶端從別處獲取信息。很不巧的是,我負責的模塊正是充當消息中轉站的作用,為了解決這個需求我才有了了解這種機制的機會。
  • 正文:由于涉及到不同模塊之間的通信,其中又包含了web前端,為了保持通信協議的一致性項目采用了ws協議,即websocket。

http協議和ws協議:最直觀的特點就是訪問地址的寫法上略有不同,兩種訪問分別為http://ip:port、ws://ip:port。http協議訪問采用一問一答的方式——客戶端發起請求到服務端,服務端收到請求后返回對應的信息,通信結束。雖然可以利用ajax發起異步的http請求,不過都是一次訪問后連接就斷開(ajax輪詢可以解決此問題,對服務器資源消耗較大);ws協議建立于TCP協議之上,我們觀察ws的頭部信息會發現一件有意思的事情

HttpObjectAggregator$AggregatedFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: CompositeByteBuf(ridx: 0, widx: 0, cap: 0, components=0))
GET / HTTP/1.1
Host: localhost:8888
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Sec-WebSocket-Key: RLnvly29Zl3sJQOfGFjO9w==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
content-length: 0

websocket建立時是以http協議握手,當建立連接之后就不需要http之間雙向通信。協議深層次的東西以我目前的能力是無法理解的,將來有機會我會再回過頭來分析底層協議。那么接下來就進入我們的主題。

引入maven依賴(結合項目實際情況而定):

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha2</version>
</dependency>

我們的需求自己既是服務端向其他模塊推送消息,又是客戶端從別處獲取消息后推送其他模塊。那么我們要在自己項目中集成netty客戶端和服務端,因為客戶端無法給多個連接推送消息。這里我主要介紹
SimpleChannelInboundHandler類的三個方法:

1. channelActive

private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
         System.out.println("客戶端加入連接:"+ctx.channel());
      //UserChannelUtil封裝了channelGroup
        UserChannelUtil.getChannelGroup().add(ctx.channel());
    }

這個方法會在有客戶端連接上來時執行,具體作用很多,通常是獲取客戶端的通道號加入到ChannelGroup中,例如注意這個GlobalEventExecutor.INSTANCE是單例,那么就意味著我們操作的是同一個對象,我們將連接的通道加入后將來就可以實現批量推送。

2.channelInactive

 @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //斷開連接
        System.out.println("客戶端斷開連接:"+ctx.channel());
        UserChannelUtil.getChannelGroup().remove(ctx.channel());
    }

它表示在客戶端離開時會觸發該事件,在這個方法內我們可以做一些收尾工作——把通道號去除,避免了通過列表的積累造成管理混亂。

3.channelRead

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("收到客戶端:"+ctx.channel()+"的消息:n"+msg.text())
    }

很顯然它就是在收到消息后會執行該事件,客戶端和服務端的方法都是相同的。

重點:netty主要是通過連接時產生的通道channel進行消息的推送,只要拿到這個channe就能對任意的客戶端推送消息,我們分析以下場景:當客戶端連接服務端時會產生一個channel,觀察channelRead()方法里面一個參數是channel,另一個則是接收的消息 。現在我們的任務就是獲取服務端channelRead()的channel,在客戶端的channelRead()中調用服務端的channelRead()方法,再把剛剛獲取的服務端channel傳進去這樣通道就以及打通了,我們只需要把客戶端傳來的消息試試傳入就完成了我們的需求。

首先建立通道號保存的對象

@Data
public class ServerChannel{
  private static Channel serverChannel;
}

從服務端獲取通道號

  @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
      ServerChannel.setServerChannel(ctx.channel());
        System.out.println("收到客戶端:"+ctx.channel()+"的消息:n"+msg.text())
    }

在客戶端調用服務端的方法

@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("收到服務端:"+ctx.channel()+"的消息:n"+msg.text())
      //通過反射創建服務端對象
      Class<WebSocketServerHandler> SocketHandler=WebSocketServerHandler.class;
       WebSocketServerHandler socketHandler=SocketHandler.newInstance();
						//獲取服務端的通道號
        ChannelHandlerContext serverChannel=ServerCtx.getContext();
       if(serverChannel !=null){
                socketHandler.channelRead(serverCtx,msg);
            }
  • 結尾:說了一大堆做法就這么簡單,分析問題的過程很漫長,理清思路就能高效解決問題。在這里給大家一個提示:netty握手協議內容的大小寫敏感,很有可能會因為不同語言的websocket類庫不同導致握手不成功,這時就需要重寫netty的頭部握手協議。如有不足之處請各位大佬們指正。

分享到:
標簽: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

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