译者:刘滨浩
作者:
https://binhao.blog.csdn.net/2021年了,还有不全力支持该游戏的音频中文网站吗,现在各式各样该游戏动作游戏不断涌现,抽奖活动,ppt都上该游戏动作游戏了,不整个该游戏都平心而论了,今天本栏就抽时间做了两个动态音频该游戏可视化功能的同时实现,不得已说这种的方式为看音频看现场直播,短文PPT,抽奖活动等方式增加了许多快感。
1 控制技术THF1
1.1 netty
非官方对于netty的叙述:
https://netty.io/
主要关键字叙述:netty是触发器设计模式互联网架构,可做各式各样协定伺服器端,因此全力支持了FTP,SMTP,HTTP等很多协定,因此操控性,灵活性,灵活性都很酷。
能看到netty总体构架Bouzemont了三个部分:
以零复本,连续性USB,扩充事件数学模型的下层核心。Socket,Datagram,Pipe,Http Tunnel做为传输传播方式。传输全力支持的各式各样协定,HTTP&WebSocket,SSL,大文档,zlib/gzip填充,文档,十进制,Google Protobuf等各式各样各式各样的传输方式。1.2 WebSocket
WebSocket是一种在一般而言TCP相连上展开串行通讯的协定。WebSocket通讯协定于2011年被IETF订为国际标准RFC 6455,并由RFC7936补足规范化。WebSocket API也被W3C订为国际标准。
WebSocket使得应用程序和流控制的数据传输变得更为单纯,容许伺服器端积极主动向应用程序发送数据。在WebSocket API中,应用程序和伺服器只需要完成一次击掌,二者之间就直接能建立无毒性的相连,并展开单向数据传输。
1.3 为什么做这种的控制技术THF1。
由上述由此可知,动态现场直播可视化做为交互式是两个单向数据传输过程。所以使用webSocket。netty本身全力支持了webSocket协定的同时实现,让同时实现更为单纯方便快捷。2 同时实现路子
2.1 服务构架
总体构架是所有应用程序都和我的伺服器端迈入两个单向地下通道的构架。
2.2 传输业务流程
3 同时实现效用
3.1 音频展现
先看看效用吧,是不是perfect,接下去就来看具体标识符是怎么同时实现的吧。
音频现场直播该游戏实例
4 标识符同时实现
4.1 工程项目结构
两个maven工程项目,将标识符放两个包下就行。
4.2 Java伺服器端
Java伺服器端标识符,总共三个类,Server,Initailizer和 Handler。
4.2.1 先做两个netty nio的伺服器端:
两个nio的服务,迈入两个tcp端口。
/** * Copyright(c)lbhbinhao@163.com * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / /| * +/_____/ | /_____/ | /_____/ | * | | | | | | | | | * | | | | | |________| | | * | | | | | / | | | * | | | | |/___________| | | * | | |___________________ | |____________| | | * | | / / | | | | | | | * | |/ _________________/ / | | / | | / * |_________________________|/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) { } }4.2.2 伺服器端的具体处理逻辑
/** * Copyright(c)lbhbinhao@163.com * * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / /| * +/_____/ | /_____/ | /_____/ | * | | | | | | | | | * | | | | | |________| | | * | | | | | / | | | * | | | | |/___________| | | * | | |___________________ | |____________| | | * | | / / | | | | | | | * | |/ _________________/ / | | / | | / * |_________________________|/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()); } }后台处理逻辑,接受到消息,写出到所有的应用程序:
/** * Copyright(c)lbhbinhao@163.com * * @author liubinhao * @date 2021/1/14 * ++++ ______ ______ ______ * +++/ /| / /| / /| * +/_____/ | /_____/ | /_____/ | * | | | | | | | | | * | | | | | |________| | | * | | | | | / | | | * | | | | |/___________| | | * | | |___________________ | |____________| | | * | | / / | | | | | | | * | |/ _________________/ / | | / | | / * |_________________________|/b |_____|/ |_____|/ */ public class BulletChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { // 用于记录和管理所有应用程序的channel public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // 获取应用程序传输过来的消息 String content = msg.text(); System.err.println("收到消息:"+ content); channels.writeAndFlush(new TextWebSocketFrame(content)); System.err.println("写出消息完成:"+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("应用程序被移除,channelId为:" + channelId); channels.remove(ctx.channel()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 发生异常之后关闭相连(关闭channel),随后从ChannelGroup中移除 ctx.channel().close(); channels.remove(ctx.channel()); } }4.3 网页应用程序同时实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Netty音频该游戏同时实现 Author:Binhao Liu</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 () { // Web Socket 已相连上,使用 send() 方法发送数据 alert("数据发送中..."); }; ws.onmessage = function (e) { console.log("接受到消息:"+e.data); createEle(e.data); }; ws.onclose = function () { // 关闭 websocket alert("相连已关闭..."); }; 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="该游戏发送[]~(^v^)~*"/> <div class="send-btn" onclick="javascript:sendMsg(document.querySelector(.con).value)">发送</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); //获取.box元素 var cW = oBox.offsetWidth; //获取box的宽度 var cH = oBox.offsetHeight; //获取box的高度 function createEle(txt) { //动态生成span标签 var oMessage = document.createElement(span); //建立标签 oMessage.innerHTML = txt; //接收参数txt因此生成替换内容 oMessage.style.left = cW + px; //初始化生成位置x oBox.appendChild(oMessage); //把标签塞到oBox里面 roll.call(oMessage, { //call改变函数内部this的指向 timing: [linear, ease-out][~~(Math.random() * 2)], color: # + (~~(Math.random() * (1 << 24))).toString(16), top: random(0, cH), fontSize: random(16, 32) }); } function roll(opt) { //该游戏滚动 //如果对象中不存在timing 初始化 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); //获取当前left的值 this.style.color = opt.color; //初始化颜色 this.style.top = opt.top + px; this.style.fontSize = opt.fontSize + px; this.timer = setInterval(function () { if (this._left <= 100) { clearInterval(this.timer); //终止定时器 this.parentNode.removeChild(this); return; //终止函数 } switch (opt.timing) { case linear: //如果匀速 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>这种两个动态的音频该游戏功能就完成啦,是不是很单纯,各位小伙伴快来试试吧。
5 小结
上班撸标识符,下班继续撸标识符写博客,这个还是很单纯,本栏写这个的时候一会儿就写完了,不过这也得益于本栏很久以前就写过netty的服务,对于Http,Tcp之类协定也比较熟悉,只有前端会有些难度,问下度娘,也很快能做完,在此分享出来与诸君分享,有问题可找本栏交流。
请立即点击咨询我们或拨打咨询热线: ,我们会详细为你一一解答你心中的疑难。项目经理在线