继续之前的例子(netty5心跳与业务消息分发实例),我们在NettyClientHandler把业务消息改为阻塞性的:

package com.wlf.netty.nettyclient.handler;

import com.wlf.netty.nettyapi.javabean.Header;
import com.wlf.netty.nettyapi.javabean.NettyMessage;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.concurrent.TimeUnit; /**
* 客户端处理类
*/
@Slf4j
public class NettyClientHandler extends ChannelHandlerAdapter { private static final String AUDIO_PATH = "D:\\input\\寒号鸟.wav"; @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage nettyMessage = (NettyMessage) msg; // 接收控制数据响应消息成功,每5秒发送pcm数据
if (nettyMessage.getHeader() != null && nettyMessage.getHeader().getType() == (byte) 0) {
// ctx.writeAndFlush(buildClientRequest());
// }
// 音频文件总时长,单位:秒
int audioTotal = 122;
try (RandomAccessFile raf = new RandomAccessFile(AUDIO_PATH, "r")) { // 读结束标志
boolean readFinish = false; // 文件总字节数
long audioLength = raf.length(); // 每次发送字节数
long eachLength = audioLength * 5 / audioTotal; // 音频数据
byte[] audioData = null;
byte[] bytes = new byte[1024]; long cuccrentLength = 0L; // 读取音频文件
while (true) {
// 休眠5秒
TimeUnit.SECONDS.sleep(5); // 获取当前时间
long startTime = System.currentTimeMillis();
while (cuccrentLength <= eachLength) { // 获取5秒内的音频字节流
int len = raf.read(bytes);
if (len == -1) {
readFinish = true;
break;
} bytes = Arrays.copyOf(bytes, len);
audioData = ArrayUtils.addAll(audioData, bytes);
cuccrentLength += len;
} // 发送5秒的数据包
NettyMessage nettyClientApi = buildNettyClientRequest(audioData, startTime);
log.info("[client] send client msg : {}", nettyClientApi);
ctx.writeAndFlush(nettyClientApi); // 读完了
if (readFinish) {
log.info("The audio data send finish...");
break;
} // 重置
cuccrentLength = 0L;
}
}
}
} /**
* long转字节
*
* @param values
* @return
*/
private byte[] longToBytes(long values) {
byte[] buffer = new byte[8];
for (int i = 0; i < 8; i++) {
int offset = 64 - (i + 1) * 8;
buffer[i] = (byte) ((values >> offset) & 0xff);
}
return buffer;
} /**
* 将两个数组合并起来
*
* @param array1
* @param array2
* @return
*/
private byte[] addAll(byte[] array1, byte... array2) {
byte[] joinedArray = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
return joinedArray;
} /**
* 在处理过程中引发异常时被调用
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("[Client] netty client request error: {}", cause.getMessage());
ctx.close();
} /**
* 创建请求消息体
*
* @param audioData
* @param time
* @return
*/
private NettyMessage buildNettyClientRequest(byte[] audioData, long time) {
NettyMessage nettyMessage = new NettyMessage();
Header header = new Header();
byte[] data = buildPcmData(audioData, time);
header.setDelimiter(0xABEF0101);
header.setLength(data.length);
header.setType((byte) 1);
header.setReserved((byte) 0);
nettyMessage.setHeader(header); // 设置数据包
nettyMessage.setData(data);
return nettyMessage;
} /**
* 构造PCM请求消息体
*
* @return
*/
private byte[] buildPcmData(byte[] audioData, long time) {
byte[] timeByte = longToBytes(time); return addAll(timeByte, audioData);
} }

  重启客户端,会发现输出变成这样:

23:35:34.339 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] control response is OK, header : Header{delimiter=-1410399999, length=8, type=0, reserved=0}. sid : 56, interval : 5000
23:35:48.216 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@60deb0fd}
23:35:53.259 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=323592, type=1, reserved=0}, data=[B@6f7f091e}
23:35:58.319 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=485384, type=1, reserved=0}, data=[B@1c9231b2}
23:36:03.361 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=647176, type=1, reserved=0}, data=[B@35f278be}
23:36:08.433 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=808968, type=1, reserved=0}, data=[B@20be6fa5}
23:36:13.496 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=970760, type=1, reserved=0}, data=[B@371eb555}
23:36:18.607 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1132552, type=1, reserved=0}, data=[B@3a8c0da5}
23:36:23.694 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1294344, type=1, reserved=0}, data=[B@1c9da5c2}
23:36:28.855 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1456136, type=1, reserved=0}, data=[B@4f0d32b3}
23:36:33.974 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1617928, type=1, reserved=0}, data=[B@d7b821a}
23:36:39.134 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1779720, type=1, reserved=0}, data=[B@57404735}
23:36:44.272 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=1941512, type=1, reserved=0}, data=[B@26825baa}
23:36:49.410 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2103304, type=1, reserved=0}, data=[B@bc7d63}
23:36:54.650 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2265096, type=1, reserved=0}, data=[B@5106443c}
23:36:59.816 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2426888, type=1, reserved=0}, data=[B@4aac8c6}
23:37:05.009 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2588680, type=1, reserved=0}, data=[B@30419cf2}
23:37:10.200 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2750472, type=1, reserved=0}, data=[B@53f5b8fc}
23:37:15.416 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=2912264, type=1, reserved=0}, data=[B@3031311a}
23:37:20.633 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=3074056, type=1, reserved=0}, data=[B@628f3322}
23:37:25.886 [nioEventLoopGroup-1-0] INFO com.wlf.netty.nettyclient.handler.NettyClientHandler - [client] send client msg : NettyMessage{header=Header{delimiter=-1410399999, length=3235848, type=1, reserved=0}, data=[B@5e95858d}

  心跳根本没进来,因为业务消息占用了事件循环的IO线程,还轮不到心跳消息的发送,除非当前的业务消息发送完了。反之亦然,如果是先发送心跳,那业务消息就别指望有机会发送了,因为心跳根本就停不下来。怎么办?两种解决方案,一种是采用netty自带的IdleStateHandler来做心跳,它不会占用IO线程,因为它采用的是事件检测;另一种就是把业务消息和心跳消息糅合到一起,既然都是定时发送,那就放一起好了,只不过这样一来定时的时间间隔就必须一致了。我们在心跳Handler中带上业务消息:

package com.wlf.netty.nettyclient.handler;

import com.wlf.netty.nettyapi.javabean.Header;
import com.wlf.netty.nettyapi.javabean.NettyMessage;
import com.wlf.netty.nettyapi.util.CommonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.extern.slf4j.Slf4j; import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.concurrent.TimeUnit; @Slf4j
public class HeartBeatClientHandler extends ChannelHandlerAdapter {
private static final String AUDIO_PATH = "D:\\input\\寒号鸟.wav";
private volatile int interval = 5000;
private volatile ScheduledFuture<?> heartBeat; @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage nettyMessage = (NettyMessage) msg; // 接收控制数据响应消息成功,发送心跳给服务端
if (nettyMessage.getHeader() != null && nettyMessage.getHeader().getType() == (byte) 0) {
byte[] data = nettyMessage.getData();
ByteBuf buf = Unpooled.buffer(8);
buf.writeBytes(data);
int sid = buf.readInt();
interval = buf.readInt();
log.info("[client] control response is OK, header : {}. sid : {}, interval : {}", nettyMessage.getHeader(), sid, interval); // 每interval(默认5000)豪秒发送一次心跳请求到服务端
// heartBeat = ctx.executor().scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
// NettyMessage heartBeat = buildHeartBeat(sid);
// log.info("[client] Client send heart beat message to server : ----> {}", heartBeat);
// ctx.writeAndFlush(heartBeat);
// }
// },
// 0, interval, TimeUnit.MILLISECONDS); // 音频文件总时长,单位:秒
int audioTotal = 122;
try (RandomAccessFile raf = new RandomAccessFile(AUDIO_PATH, "r")) { // 读结束标志
boolean readFinish = false; // 文件总字节数
long audioLength = raf.length(); // 每次发送字节数
long eachLength = audioLength * 5 / audioTotal; // 音频数据
byte[] audioData = null;
byte[] bytes = new byte[1024]; long cuccrentLength = 0L; // 读取音频文件
while (true) {
// 休眠5秒
TimeUnit.SECONDS.sleep(5); // 获取当前时间
long startTime = System.currentTimeMillis();
do { // 获取5秒内的音频字节流
int len = raf.read(bytes);
if (len == -1) {
readFinish = true;
break;
} bytes = Arrays.copyOf(bytes, len);
audioData = ArrayUtils.addAll(audioData, bytes);
cuccrentLength += len;
} while (cuccrentLength <= eachLength); // 发送心跳
NettyMessage heartBeat = buildHeartBeat(sid);
log.info("[client] Client send heart beat message to server : ----> {}", heartBeat);
ctx.writeAndFlush(heartBeat); // 发送5秒的数据包
NettyMessage nettyClientApi = buildNettyClientRequest(audioData, startTime);
log.info("[client] Client send business message to server : ----> {}", nettyClientApi);
ctx.writeAndFlush(nettyClientApi); // 读完了
if (readFinish) {
log.info("The audio data send finish...");
break;
} // 重置
cuccrentLength = 0L;
audioData = null;
}
}
} else if (nettyMessage.getHeader() != null && nettyMessage.getHeader().getType() == (byte) 2) {
log.info("[client] receive server business : {}", nettyMessage);
} else {
ctx.fireChannelRead(msg);
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("[Client] heart request error: {}", cause.getMessage());
if (heartBeat != null) {
heartBeat.cancel(true);
heartBeat = null;
}
ctx.fireExceptionCaught(cause);
} /**
* 构造心跳请求消息体
*
* @return
*/
private NettyMessage buildHeartBeat(int sid) {
NettyMessage message = new NettyMessage();
Header header = new Header();
byte[] data = buildData(sid);
header.setDelimiter(0xABEF0101);
header.setLength(data.length);
header.setType((byte) 3);
header.setReserved((byte) 0);
message.setHeader(header); // 设置数据包
message.setData(data);
return message;
} /**
* 构建心跳响应消息体
*
* @param sid
* @return
*/
private byte[] buildData(int sid) {
ByteBuf result = Unpooled.buffer(4);
result.writeInt(sid);
return result.array();
} /**
* 创建请求消息体
*
* @param audioData
* @param time
* @return
*/
private NettyMessage buildNettyClientRequest(byte[] audioData, long time) {
NettyMessage nettyMessage = new NettyMessage();
Header header = new Header();
byte[] data = buildPcmData(audioData, time);
header.setDelimiter(Delimiter.DELIMITER);
header.setLength(data.length);
header.setType(MessageType.PCM_TYPE.getType());
header.setReserved((byte) 0);
nettyMessage.setHeader(header); // 设置数据包
nettyMessage.setData(data);
return nettyMessage;
} /**
* 构造PCM请求消息体
*
* @return
*/
private byte[] buildPcmData(byte[] audioData, long time) {
byte[] timeByte = CommonUtil.longToBytes(time); return addAll(timeByte, audioData);
} /**
* long转字节
*
* @param values
* @return
*/
private byte[] longToBytes(long values) {
byte[] buffer = new byte[8];
for (int i = 0; i < 8; i++) {
int offset = 64 - (i + 1) * 8;
buffer[i] = (byte) ((values >> offset) & 0xff);
}
return buffer;
} /**
* 将两个数组合并起来
*
* @param array1
* @param array2
* @return
*/
private byte[] addAll(byte[] array1, byte... array2) {
byte[] joinedArray = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
return joinedArray;
} }

  至于原来的NettyClientHandler相当于废了,在引导类中名存实亡。重启NettyClient,输出如下:

15:45:07.442 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] control response is OK, header : Header{delimiter=-1410399999, length=8, type=0, reserved=0}. sid : 94, interval : 5000
15:45:12.499 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@2bf023ed}
15:45:12.504 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send business message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@b1ad25a}
15:45:17.519 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@44fb731d}
15:45:17.520 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send business message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@253b550c}
15:45:22.551 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@f7ef50d}
15:45:22.552 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send business message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@52ab6eba}
15:45:27.565 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@4d578c69}
15:45:27.565 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send business message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@323b23fa}
15:45:32.598 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@4a957e2d}
15:45:32.598 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send business message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=161800, type=1, reserved=0}, data=[B@43c2077b}
15:45:37.623 [nioEventLoopGroup-1-2] INFO com.wlf.netty.nettyclient.handler.HeartBeatClientHandler - [client] Client send heart beat message to server : ----> NettyMessage{header=Header{delimiter=-1410399999, length=4, type=3, reserved=0}, data=[B@3207ffae}

netty5心跳与阻塞性业务消息分发实例的更多相关文章

  1. netty5心跳与业务消息分发实例

    继续基于我们之前的例子(参见netty5自定义私有协议实例),这次我们加上连接校验和心跳机制: 只要校验通过,客户端发送心跳和业务消息是两个不同的事件发送的,彼此互不干扰.针对以上流程,我们需要增加4 ...

  2. .net 分布式架构之业务消息队列

    开源QQ群: .net 开源基础服务  238543768 开源地址: http://git.oschina.net/chejiangyi/Dyd.BusinessMQ ## 业务消息队列 ##业务消 ...

  3. Android 消息分发机制

    Android 中针对耗时的操作,放在主线程操作,轻者会造成 UI 卡顿,重则会直接无响应,造成 Force Close.同时在 Android 3.0 以后,禁止在主线程进行网络请求. 针对耗时或者 ...

  4. cocos creator主程入门教程(六)—— 消息分发

    五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑.本系列文章以TypeScript为介绍语言. 本篇开始介绍游戏业务架构相关的内容.在游戏业务层,所有需要隔离的系统和模块间通信都可以通过消息分发解耦. ...

  5. 一个可以代替冗长switch-case的消息分发小框架

    在项目中,我需要维护一个应用层的字节流协议.这个协议的每条报文都是一个字节数组,数组的头两个字节表示消息的传送方向,第三.四个字节表示消息ID,也就是消息种类,再往后是消息内容.时间戳.校验码等……整 ...

  6. 使用Netty4实现基本的消息分发

    示例工程代码 可从附件下载 具体的说明和用法在后面介绍 需求与目的 一个游戏服务端需要处理各种业务逻辑,每一种业务逻辑都对应着一个请求消息和一个响应消息.那么服务端需要把这些不同的消息自动分发到对应的 ...

  7. Kafka分片存储、消息分发和持久化机制

    Kafka 分片存储机制 Broker:消息中间件处理结点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka集群. Topic:一类消息,例如 page vi ...

  8. 深入详解美团点评CAT跨语言服务监控(四)服务端消息分发

    这边首先介绍下大众点评CAT消息分发大概的架构如下: 图4 消息分发架构图 分析管理器的初始化 我们在第一章讲到服务器将接收到的消息交给解码器(MessageDecoder)去做解码最后交给具体的消费 ...

  9. nodejs选择JavaScript作为开发语言,是因为一般的开发语言的标准库都是带有IO模块的,并且通常这个 模块是阻塞性的,所以nodejs选择了没有自带IO模块的Javascript

    Javascrip本身不带IO功能,nodejs选择JavaScript作为开发语言,是因为一般的开发语言的标准库都是带有IO模块的,并且通常这个 模块是阻塞性的,所以nodejs选择了没有自带IO模 ...

随机推荐

  1. JDK源码那些事儿之LinkedTransferQueue

    在JDK8的阻塞队列实现中还有两个未进行说明,今天继续对其中的一个阻塞队列LinkedTransferQueue进行源码分析,如果之前的队列分析已经让你对阻塞队列有了一定的了解,相信本文要讲解的Lin ...

  2. 基于h5+的微信支付,hbuilder打包

    1.打开app项目的manifest.json的文件,选择模块权限配置,将Payment(支付)模块添加至已选模块中 2.选择SDK配置,在plus.payment·支付中,勾选□ 微信支付,配置好a ...

  3. service worker(一)之离线应用

    serviceWork.html <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  4. ArrayList 集合的几种遍历的方法

    ArrayList 集合  也可称作动态数组(长度可变),在新建的时候是没有默认长度的,在新增数据长度小于10的时候,ArrayList 的长度会自动设置为10 //了解更多可以按住Ctrl 再点击你 ...

  5. Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]

    1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...

  6. leetcode解题报告(28):Remove Linked List Elements

    描述 Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 ...

  7. luogu 3466 对顶堆

    显然答案是将一段区间全部转化成了其中位数这样的话,需要维护一个数据结构支持查询当前所有数中位数对顶堆 用两个堆将 < 中位数的数放入大根堆将 > 中位数的数放入小根堆这样就会存在删除操作 ...

  8. rocketMq和kafka的架构区别

    概述 其实一直想写一篇rocketMq和kafka在架构设计上的差别,但是一直有个问题没搞明白所以迟迟没动手,今天无意中听人点播了一下似乎明白了这个问题,所以就有了这篇对比. 这篇博文主要讲清楚kaf ...

  9. 用avalon框架怎么做轮播图?

    avalon这个框架其实特别的小众,做个轮播图呢?在github上的例子只有一个,而且功能特别的少,有的引入的插件与avalon里面的指令又不兼容,所以找了一个owl-carousel,目前实现了移动 ...

  10. OpenFOAM显示残差

    本文主要讲解两种方法用来显示OpenFOAM的计算残差,一种是采用OpenFOAM自带的foamMonitor来输出残差,另一种就是大家经常看见的采用pyFoam来输出残差.不管采用哪一种方法都必须安 ...