日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
老板怒吼:今晚整一個B站彈幕交互功能

圖片來自 包圖網(wǎng)

建華網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、自適應(yīng)網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護(hù)。創(chuàng)新互聯(lián)公司于2013年創(chuàng)立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。

今天筆者就抽空做了一個實時視頻彈幕交互的小功能,不得不說這樣的形式為看視頻看直播,講義 PPT,抽獎等形式增加了許多樂趣。

技術(shù)選型

①Netty

官方對于 Netty 的描述:

 
 
 
 
  1. https://netty.io/ 

主要關(guān)鍵詞描述:Netty 是異步事件驅(qū)動網(wǎng)絡(luò)框架,可做各種協(xié)議服務(wù)端,并且支持了 FTP,SMTP,HTTP 等很多協(xié)議,并且性能,穩(wěn)定性,靈活性都很棒。

可以看到 Netty 整體架構(gòu)上分了三個部分:

  • 以零拷貝,一致性接口,擴(kuò)展事件模型的底層核心。
  • Socket,Datagram,Pipe,Http Tunnel 作為傳輸媒介。
  • 傳輸支持的各種協(xié)議,HTTP&WebSocket,SSL,大文件,zlib/gzip 壓縮,文本,二進(jìn)制,Google Protobuf 等各種各種的傳輸形式。

②WebSocket

WebSocket 是一種在單個 TCP 連接上進(jìn)行全雙工通信的協(xié)議。WebSocket 通信協(xié)議于 2011 年被 IETF 定為標(biāo)準(zhǔn) RFC 6455,并由 RFC7936 補充規(guī)范。

WebSocket API 也被 W3C 定為標(biāo)準(zhǔn)。WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。

在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

為什么做這樣的技術(shù)選型:

  • 由上述可知,實時直播交互作為互動式是一個雙向數(shù)據(jù)傳輸過程。所以使用 WebSocket。
  • Netty 本身支持了 WebSocket 協(xié)議的實現(xiàn),讓實現(xiàn)更加簡單方便。

實現(xiàn)思路

①服務(wù)架構(gòu)

整體架構(gòu)是所有客戶端都和我的服務(wù)端開啟一個雙向通道的架構(gòu)。

②傳輸流程

如下圖:

實現(xiàn)效果

先看看效果吧,是不是 perfect,接下來就來看具體代碼是怎么實現(xiàn)的吧。

視頻直播彈幕示例

代碼實現(xiàn)

①項目結(jié)構(gòu)

一個 maven 項目,將代碼放一個包下就行。

②Java 服務(wù)端

Java 服務(wù)端代碼,總共三個類,Server,Initailizer 和 Handler。

先做一個 netty nio 的服務(wù)端:一個 nio 的服務(wù),開啟一個 tcp 端口。

 
 
 
 
  1. import io.netty.bootstrap.ServerBootstrap; 
  2. import io.netty.channel.ChannelFuture; 
  3. import io.netty.channel.EventLoopGroup; 
  4. import io.netty.channel.nio.NioEventLoopGroup; 
  5. import io.netty.channel.socket.nio.NioServerSocketChannel; 
  6.  
  7. /** 
  8.  * Copyright(c)lbhbinhao@163.com 
  9.  * @author liubinhao 
  10.  * @date 2021/1/14 
  11.  * ++++ ______                           ______             ______ 
  12.  * +++/     /|                         /     /|           /     /| 
  13.  * +/_____/  |                       /_____/  |         /_____/  | 
  14.  * |     |   |                      |     |   |        |     |   | 
  15.  * |     |   |                      |     |   |________|     |   | 
  16.  * |     |   |                      |     |  /         |     |   | 
  17.  * |     |   |                      |     |/___________|     |   | 
  18.  * |     |   |___________________   |     |____________|     |   | 
  19.  * |     |  /                  / |  |     |   |        |     |   | 
  20.  * |     |/ _________________/  /   |     |  /         |     |  / 
  21.  * |_________________________|/b    |_____|/           |_____|/ 
  22.  */ 
  23. public enum BulletChatServer { 
  24.     /** 
  25.      * Server instance 
  26.      */ 
  27.     SERVER; 
  28.  
  29.     private BulletChatServer(){ 
  30.         EventLoopGroup mainGroup = new NioEventLoopGroup(); 
  31.         EventLoopGroup subGroup  = new NioEventLoopGroup(); 
  32.         ServerBootstrap server = new ServerBootstrap(); 
  33.         server.group(mainGroup,subGroup) 
  34.                 .channel(NioServerSocketChannel.class) 
  35.                 .childHandler(new BulletChatInitializer()); 
  36.         ChannelFuture future = server.bind(9123); 
  37.     } 
  38.  
  39.     public static void main(String[] args) { 
  40.  
  41.     } 
  42.  

服務(wù)端的具體處理邏輯:

 
 
 
 
  1. import io.netty.channel.ChannelInitializer; 
  2. import io.netty.channel.ChannelPipeline; 
  3. import io.netty.channel.socket.SocketChannel; 
  4. import io.netty.handler.codec.http.HttpObjectAggregator; 
  5. import io.netty.handler.codec.http.HttpServerCodec; 
  6. import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 
  7. import io.netty.handler.stream.ChunkedWriteHandler; 
  8. import io.netty.handler.timeout.IdleStateHandler; 
  9.  
  10. /** 
  11.  * Copyright(c)lbhbinhao@163.com 
  12.  * 
  13.  * @author liubinhao 
  14.  * @date 2021/1/14 
  15.  * ++++ ______                           ______             ______ 
  16.  * +++/     /|                         /     /|           /     /| 
  17.  * +/_____/  |                       /_____/  |         /_____/  | 
  18.  * |     |   |                      |     |   |        |     |   | 
  19.  * |     |   |                      |     |   |________|     |   | 
  20.  * |     |   |                      |     |  /         |     |   | 
  21.  * |     |   |                      |     |/___________|     |   | 
  22.  * |     |   |___________________   |     |____________|     |   | 
  23.  * |     |  /                  / |  |     |   |        |     |   | 
  24.  * |     |/ _________________/  /   |     |  /         |     |  / 
  25.  * |_________________________|/b    |_____|/           |_____|/ 
  26.  */ 
  27.  
  28. public class BulletChatInitializer extends ChannelInitializer { 
  29.     @Override 
  30.     protected void initChannel(SocketChannel ch) throws Exception { 
  31.         ChannelPipeline pipeline = ch.pipeline(); 
  32.         pipeline.addLast(new HttpServerCodec()); 
  33.         pipeline.addLast(new ChunkedWriteHandler()); 
  34.         pipeline.addLast(new HttpObjectAggregator(1024*64)); 
  35.         pipeline.addLast(new IdleStateHandler(8, 10, 12)); 
  36.         pipeline.addLast(new WebSocketServerProtocolHandler("/lbh")); 
  37.         pipeline.addLast(new BulletChatHandler()); 
  38.     } 

后臺處理邏輯,接受到消息,寫出到所有的客戶端:

 
 
 
 
  1. import io.netty.channel.Channel; 
  2. import io.netty.channel.ChannelHandler; 
  3. import io.netty.channel.ChannelHandlerContext; 
  4. import io.netty.channel.SimpleChannelInboundHandler; 
  5. import io.netty.channel.group.ChannelGroup; 
  6. import io.netty.channel.group.DefaultChannelGroup; 
  7. import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 
  8. import io.netty.util.concurrent.EventExecutorGroup; 
  9. import io.netty.util.concurrent.GlobalEventExecutor; 
  10.  
  11. /** 
  12.  * Copyright(c)lbhbinhao@163.com 
  13.  * 
  14.  * @author liubinhao 
  15.  * @date 2021/1/14 
  16.  * ++++ ______                           ______             ______ 
  17.  * +++/     /|                         /     /|           /     /| 
  18.  * +/_____/  |                       /_____/  |         /_____/  | 
  19.  * |     |   |                      |     |   |        |     |   | 
  20.  * |     |   |                      |     |   |________|     |   | 
  21.  * |     |   |                      |     |  /         |     |   | 
  22.  * |     |   |                      |     |/___________|     |   | 
  23.  * |     |   |___________________   |     |____________|     |   | 
  24.  * |     |  /                  / |  |     |   |        |     |   | 
  25.  * |     |/ _________________/  /   |     |  /         |     |  / 
  26.  * |_________________________|/b    |_____|/           |_____|/ 
  27.  */ 
  28.  
  29. public class BulletChatHandler  extends SimpleChannelInboundHandler { 
  30.     // 用于記錄和管理所有客戶端的channel 
  31.     public static ChannelGroup channels = 
  32.             new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 
  33.     @Override 
  34.     protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { 
  35.         // 獲取客戶端傳輸過來的消息 
  36.         String content = msg.text(); 
  37.         System.err.println("收到消息:"+ content); 
  38.         channels.writeAndFlush(new TextWebSocketFrame(content)); 
  39.         System.err.println("寫出消息完成:"+content); 
  40.     } 
  41.  
  42.     @Override 
  43.     public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 
  44.         channels.add(ctx.channel()); 
  45.     } 
  46.  
  47.     @Override 
  48.     public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 
  49.  
  50.         String channelId = ctx.channel().id().asShortText(); 
  51.         System.out.println("客戶端被移除,channelId為:" + channelId); 
  52.         channels.remove(ctx.channel()); 
  53.     } 
  54.  
  55.     @Override 
  56.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
  57.         cause.printStackTrace(); 
  58.         // 發(fā)生異常之后關(guān)閉連接(關(guān)閉channel),隨后從ChannelGroup中移除 
  59.         ctx.channel().close(); 
  60.         channels.remove(ctx.channel()); 
  61.     } 
  62.  

③網(wǎng)頁客戶端實現(xiàn)

代碼如下:

 
 
 
 
  1.  
  2.  
  3.  
  4.      
  5.      
  6.     Netty視頻彈幕實現(xiàn) Author:Binhao Liu 
  7.      
  8.      
  9.         * { 
  10.             margin: 0px; 
  11.             padding: 0px 
  12.         } 
  13.  
  14.         html, body { 
  15.             height: 100% 
  16.         } 
  17.  
  18.         body { 
  19.             overflow: hidden; 
  20.             background-color: #FFF; 
  21.             text-align: center; 
  22.         } 
  23.  
  24.         .flex-column { 
  25.             display: flex; 
  26.             flex-direction: column; 
  27.             justify-content: space-between;, align-items: center; 
  28.         } 
  29.  
  30.         .flex-row { 
  31.             display: flex; 
  32.             flex-direction: row; 
  33.             justify-content: center; 
  34.             align-items: center; 
  35.         } 
  36.  
  37.         .wrap { 
  38.             overflow: hidden; 
  39.             width: 70%; 
  40.             height: 600px; 
  41.             margin: 100px auto; 
  42.             padding: 20px; 
  43.             background-color: transparent; 
  44.             box-shadow: 0 0 9px #222; 
  45.             border-radius: 20px; 
  46.         } 
  47.  
  48.         .wrap .box { 
  49.             position: relative; 
  50.             width: 100%; 
  51.             height: 90%; 
  52.             background-color: #000000; 
  53.             border-radius: 10px 
  54.         } 
  55.  
  56.         .wrap .box span { 
  57.             position: absolute; 
  58.             top: 10px; 
  59.             left: 20px; 
  60.             display: block; 
  61.             padding: 10px; 
  62.             color: #336688 
  63.         } 
  64.  
  65.         .wrap .send { 
  66.             display: flex; 
  67.             width: 100%; 
  68.             height: 10%; 
  69.             background-color: #000000; 
  70.             border-radius: 8px 
  71.         } 
  72.  
  73.         .wrap .send input { 
  74.             width: 40%; 
  75.             height: 60%; 
  76.             border: 0; 
  77.             outline: 0; 
  78.             border-radius: 5px 0px 0px 5px; 
  79.             box-shadow: 0px 0px 5px #d9d9d9; 
  80.             text-indent: 1em 
  81.         } 
  82.  
  83.         .wrap .send .send-btn { 
  84.             width: 100px; 
  85.             height: 60%; 
  86.             background-color: #fe943b; 
  87.             color: #FFF; 
  88.             text-align: center; 
  89.             border-radius: 0px 5px 5px 0px; 
  90.             line-height: 30px; 
  91.             cursor: pointer; 
  92.         } 
  93.  
  94.         .wrap .send .send-btn:hover { 
  95.             background-color: #4cacdc 
  96.         } 
  97.      
  98.  
  99.  
  100.  
  101.  
  102.      
  103.          
  104.     
 
  •      
  •  
  •          
  •  
  •         發(fā)送
  •  
  •     
  •  
  •  
  •  
  •  
  •  
  •  
  • 這樣一個實時的視頻彈幕功能就完成啦,是不是很簡單,各位小伙伴快來試試吧。

    小結(jié)

    這個還是很簡單,筆者寫這個的時候一會兒就寫完了。不過這也得益于筆者很久以前就寫過 Netty 的服務(wù),對于 HTTP,TCP 之類協(xié)議也比較熟悉。

    只有前端會有些難度,問下度娘,也很快能做完,在此分享出來與諸君分享,有問題可找筆者交流。

    作者:興趣使然的程序猿

    編輯:陶家龍

    出處:http://adkx.net/w71wf


    分享文章:老板怒吼:今晚整一個B站彈幕交互功能
    鏈接地址:http://www.dlmjj.cn/article/dhcoggc.html