For 2021 years, you still have a video web site does not support barrage, various barrage now play emerge in endlessly, lottery, PPT barrage on the play, the barrage is said not over, today I will take time to do a real time video barrage the realization of the function of interaction, have to say that the form of a video look at live, lecture PPT, Lotteries and so on add a lot of fun.

1 Technology selection

1.1 NetTY Official description of NetTY:

netty.io/

Netty is the asynchronous event-driven network framework, can do a variety of protocol server, and support FTP, SMTP, HTTP and many other protocols, and performance, stability, flexibility are very good.As you can see, netty’s overall architecture is divided into three parts:

  • Extend the underlying core of the event model with zero copy, consistent interface.
  • Socket, Datagram, Pipe, and Http Tunnel are used as transmission media.
  • Transfer support for various protocols, HTTP&WebSocket, SSL, large files, Zlib /gzip compression, text, binary, Google Protobuf and other various transfer forms.

1.2 WebSocket WebSocket is a protocol for full-duplex communication over a single TCP connection. The WebSocket communication protocol was standardized by THE IETF in 2011 as RFC 6455, and is supplemented by RFC7936. The WebSocket API is also a W3C standard.

WebSocket makes it easier to exchange data between the client and the server, allowing the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake to create a persistent connection and two-way data transfer.

1.3 Why do such technical selection. As can be seen from the above, real-time live broadcast interaction as an interactive process is a two-way data transmission. So use webSocket. Netty itself supports the implementation of webSocket protocol, making the implementation more simple and convenient.

2 Implementation Idea

2.1 Service ArchitectureThe overall architecture is that all clients open a two-way channel with my server. 2.2 Transmission Process

3 Implementation Effect

3.1 Video PresentationFirst look at the effect, is it perfect, then look at the specific code is how to achieve it.Example of live video live bullet screen

4 Code Implementation

4.1 Project StructureA Maven project, just put the code in a package. 4.2 Java ServerJava Server code, a total of three classes, Server, Initailizer and Handler.

4.2.1 Make a Netty NIO Server first: A NIO service with one TCP port enabled.

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; /** * Copyright(c)[email protected] * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / | * + / / | | / _____ _____ _____ / * | | | | | | | | | | * | | | | | | _____ | | | * | | | | | / | | | * | | | | * | | / ___________ | | | | | ___________________ | | ____________ hold | | | * | | / / | | | | | | | * | | I am grateful to / / / |  | / | | / * |_________________________|/b |_____|/ |_____|/ */ public enum BulletChatServer { /** * Server instance */ SERVER; private BulletChatServer(){ EventLoopGroup mainGroup = new NioEventLoopGroup(); EventLoopGroup subGroup = new NioEventLoopGroup(); ServerBootstrap server = new ServerBootstrap(); server.group(mainGroup,subGroup) .channel(NioServerSocketChannel.class) .childHandler(new BulletChatInitializer()); ChannelFuture future = server.bind(9123); } public static void main(String[] args) { } }Copy the code

4.2.2 Specific processing logic of the server

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; import io.netty.handler.timeout.IdleStateHandler; /** * Copyright(c)[email protected] * * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / | * + / / | | / _____ _____ _____ / * | | | | | | | | | | * | | | | | | _____ | | | * | | | | | / | | | * | | | | * | | / ___________ | | | | | ___________________ | | ____________ hold | | | * | | / / | | | | | | | * | | I am grateful to / / / |  | / | | / * |_________________________|/b |_____|/ |_____|/ */ public class BulletChatInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpObjectAggregator(1024*64)); pipeline.addLast(new IdleStateHandler(8, 10, 12)); pipeline.addLast(new WebSocketServerProtocolHandler("/lbh")); pipeline.addLast(new BulletChatHandler()); }}Copy the code

The background processing logic receives the message and writes it out to all clients:

import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.GlobalEventExecutor; /** * Copyright(c)[email protected] * * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / | * + / / | | / _____ _____ _____ / * | | | | | | | | | | * | | | | | | _____ | | | * | | | | | / | | | * | | | | * | | / ___________ | | | | | ___________________ | | ____________ hold | | | * | | / / | | | | | | | * | | I am grateful to / / / |  | / | | / * |_________________________|/b |_____|/ |_____|/ */ public class BulletChatHandler extends SimpleChannelInboundHandler < TextWebSocketFrame > {/ / used to record and manage all the client channel public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame MSG) throws Exception {// Obtain the message transmitted by the client. String Content = msg.text(); System.err. Println (" Received message: "+ content); channels.writeAndFlush(new TextWebSocketFrame(content)); System.err. Println (" Write message complete: "+content); } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { channels.add(ctx.channel()); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { String channelId = ctx.channel().id().asShortText(); System.out.println(" client removed, channelId: "+ channelId); channels.remove(ctx.channel()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); Ctx.channel ().close() is removed from the ChannelGroup. channels.remove(ctx.channel()); }}Copy the code

4.3 Web client implementation

<! DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> </title> <link rel="stylesheet" href=""> <style type="text/ CSS "media="screen"> margin: 0px; padding: 0px } html, body { height: 100% } body { overflow: hidden; background-color: #FFF; text-align: center; } .flex-column { display: flex; flex-direction: column; justify-content: space-between; , align-items: center; } .flex-row { display: flex; flex-direction: row; justify-content: center; align-items: center; } .wrap { overflow: hidden; width: 70%; height: 600px; margin: 100px auto; padding: 20px; background-color: transparent; box-shadow: 0 0 9px #222; border-radius: 20px; } .wrap .box { position: relative; width: 100%; height: 90%; background-color: #000000; border-radius: 10px } .wrap .box span { position: absolute; top: 10px; left: 20px; display: block; padding: 10px; color: #336688 } .wrap .send { display: flex; width: 100%; height: 10%; background-color: #000000; border-radius: 8px } .wrap .send input { width: 40%; height: 60%; border: 0; outline: 0; border-radius: 5px 0px 0px 5px; box-shadow: 0px 0px 5px #d9d9d9; text-indent: 1em } .wrap .send .send-btn { width: 100px; height: 60%; background-color: #fe943b; color: #FFF; text-align: center; border-radius: 0px 5px 5px 0px; line-height: 30px; cursor: pointer; } .wrap .send .send-btn:hover { background-color: #4cacdc } </style> </head> <script> var ws = new WebSocket("ws://localhost:9123/lbh"); Ws.onopen = function () {// If the Web Socket is connected, use the send() method to send data. ); }; Ws. onMessage = function (e) {console.log(" received message :"+e.data); createEle(e.data); }; Ws.onclose = function () {// Close websocket alert(" Connection closed... ); }; function sendMsg(msg) { ws.send(msg) } </script> <body> <div class="wrap flex-column"> <div class="box"> <video src="shape.mp4" width="100%" height="100%" controls autoplay></video> </div> <div class="send flex-row"> <input Type = "text" class = "con" placeholder = "barrage send [] ~ (^ v ^) ~ *" / > < div class = "send - BTN" Onclick ="javascript:sendMsg(document.querySelector('.con').value)"> send </div> </div> </div> <script SRC = "https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" type = "text/javascript" > < / script > < script > / / 1. Var oBox = document.querySelector('.box'); Var cW = oBox. OffsetWidth; Var cH = oBox. OffsetHeight; Function createEle(TXT) {var oMessage = document.createElement('span'); // create omessage.innerhtml = TXT; Omessage.style. left = cW + 'px'; AppendChild (oMessage); // Initialize the position x obox.appendChild (oMessage); Timing: ['linear', 'ease-out'][~~(math.random () * 2)], color: timing: ['linear', 'ease-out'][~~(math.random () * 2)] '#' + (~~(Math.random() * (1 << 24))).toString(16), top: random(0, cH), fontSize: random(16, 32) }); } function roll (opt) {/ / rolling barrage / / if the object does not exist in the timing to initialize the opt. Timing = opt. Timing | | 'linear'; opt.color = opt.color || '#fff'; opt.top = opt.top || 0; opt.fontSize = opt.fontSize || 16; this._left = parseInt(this.offsetLeft); // Get the current left value this.style.color = opt.color; // Initialize the color this.style.top = opt.top + 'px'; this.style.fontSize = opt.fontSize + 'px'; this.timer = setInterval(function () { if (this._left <= 100) { clearInterval(this.timer); / / terminate this timer. ParentNode. RemoveChild (this); return; } switch (opt.timing) {case 'linear': // If constant speed this._left += -2; break; case 'ease-out': // this._left += (0 - this._left) * .01; break; } this.style.left = this._left + 'px'; }.bind(this), 1000 / 60); } function random(start, end) {return start + ~~(math.random () * (end-start)); } var aLi = document.querySelectorAll('li'); //10 function forEach(ele, cb) { for (var i = 0, len = aLi.length; i < len; i++) { cb && cb(ele[i], i); } } forEach(aLi, function (ele, i) { ele.style.left = i * 100 + 'px'; }); Var obj = {num: 1, add: function () {this.num++; //obj.num = 2; (function () { console.log(this.num); })}}; obj.add(); //window </script> </body> </html>Copy the code

Such a real-time video bullet screen function is completed, is not very simple, you friends come to try it.

5 subtotal

Lu code to work, go off work to continue to lu code to write blog, this is very simple, when I wrote this soon finished, but it has also benefited from the author wrote long ago netty service, for Http, Tcp, such agreement is more familiar, only the front will be a little difficult, ask the baidu, also can be done soon, share it with you to share here.

Source: binhao.blog.csdn.net/article/details/112631642