目录
25.自定义编解码器
25.1 自定义编解码器编码
25.2 自定义编解码器的总结和补充
26.自定义通信协议
26.1 关于通信协议的关注点
26.2 自定义通信协议的格式
26.3 编解码
有了上面这个大体框架的流程之后,我们来聊一个非常特殊的:
比如我们在客户端想把字符串"10-20"经过编码后转为long类型,然后转为二进制存储到ByteBuf中,通过网络IO发出去,服务端接收到ByteBuf后,解码为long类型
那么在netty中是没有这么个编解码器的,所以我们需要自己去实现这个编解码器。在框架中,你要扩展自定义一个组件也好,功能也罢,需要遵循它们的规范,也就是继承它的一些接口或者实现它的一些实现类。比如:spring中的Event那个事件通知。
你自定义的东西只有实现别的规范,这样才能被框架体系发现你自定义的类,进而你自定义的东西才能和框架融为一体,融为一体后才能实现你的功能,框架才会调用你。
而对于编码器,我们需要继承的是MessageToByteEncoder,对于解码器,我们需要继承的是ByteToMessageDecoder。然后在pipline中生效,这就是它的逻辑。
于是基于这个逻辑来实现我们的自定义编解码器
需求:
1.我们在客户端发送一个字符串"10~20",这样的数据,然后我们希望发送出去的时候是以分隔符为界限,发出去两个long类型的数据
2.服务端接收到之后把数据从ByteBuf中取出来
需求分析:
这就是需要一组编解码器,编码器把字符串分隔开,然后转为两个long发出去
解码器把接收到的ByteBuf数据拿到手,解码转为long类型处理
具体实现如下:
package com.messi.netty_core_02.netty10; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //日志输出的编码器 pipeline.addLast(new LoggingHandler()); //我们自定义的编码器 pipeline.addLast(new MyLong2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush("10-20"); group.shutdownGracefully(); } }
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyLong2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyLong2ByteEncoder.class); /** * * @param ctx 上下文对象 * @param msg 等待编码的数据 * @param out 编码后的数据为二进制字节流格式,都存储到out中交给Netty,netty负责把ByteBuf数据交给socket缓冲区 * socket缓冲区会把数据交给网络IO通信发给服务端 * @throws Exception */ @Override protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception { log.info("MyLong2ByteEncoder.encode start ~~~ ") ; if (msg == null) { return; } String[] msgs = msg.split("-"); for (String message : msgs) { long longMsg = Long.parseLong(message); //每一个long类型的数据都在ByteBuf中占用8字节的大小空间 out.writeLong(longMsg); } } }
package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if(msg instanceof Long) { Long data = (Long) msg; log.info("得到的客户端输入为:{}",data) ; } } }); } }); serverBootstrap.bind(8000); } }
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder.class); /** * * @param ctx 上下文对象 * @param in 网络IO传输过来的数据,存储到ByteBuf类型的in中 * @param out 解码处理完后,把每一个"Message"都存储到out这一集合中,便于后续Netty遍历该out集合进行执行pipeline流水线的Handler操作 * Netty是以消息Message为单位进行处理数据的,有多少Message,就执行多少次pipeline * ----> * 如果字节数不超过滑动窗口,socket缓冲区,ByteBuf缓冲区,客户端只发一次数据即可,为什么服务端能划分出多个Message呢? * 原因很简单:每调用一次decode进行处理ByteBuf,那么就会封装成一个Message。 * 如果服务端一次没有处理完ByteBuf,那么会进行第二次调用decode方法的处理,则第二次处理ByteBuf,则又会生成一个新的Message * 以此类推,直到ByteBuf中的数据都处理完。 * 调用n次decode方法,处理ByteBuf n次,存储n个Message到out集合中 * ----> * 啥时候意味着ByteBuf中的数据都处理完? * 其实还是指针的移动,思考一下之前NIO的各种指针,当读指针到达limit指针边界后就意味着ByteBuf处理完毕 * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L long reciveLong = in.readLong(); out.add(reciveLong); } } } 测试输出 客户端输出: 由于自定义编码中去除了分隔符"-",所以只发送16字节的数据给服务端。注意:是一次性发送16字节的数据给服务端 服务端输出: 如下图所示,服务端自定义解码器调用了两次,为什么? 因为在自定义解码器的逻辑中,一次只处理了ByteBuf中8字节的数据大小,所以一次处理不完ByteBuf,所以会多次处理,多次处理会多次调用decode方法,会多次加入"Message"到out这一List集合中。由于out这一集合中有多个Message,所以pipeline流水线的Handler会执行多次。 总结: 首先明确一点,客户端对于这两个long类型的数字,10和20,他是只发送了一次的,因为我们首先看到这个数据的结构,其次日志只输出了一次。 再次我们来看服务端日志,数据是处理了两次的,因为输出了两次,解码器处理了两次。那么这是为 啥。 1、首先不是半包黏包,因为我们的缓冲区不至于连两个long都拿不到。 2、因为是两个消息,我们的数据在被解码器处理之后客户端那里其实是把数据处理位两个long发过来 的,服务端这里解码处理其实得到两个消息message,添加到out集合里面是两个消息。然后就处理了两次,这里有个问题就是,当你的ByteBuf的数据一次没处理完,那就会继续调用decode方法,进行再次处理,因为我们的数据是16字节,第一次值处理了八个字节,因为我们读取的就是一个readLong,long就是读取读写指针的前八个字节,所以处理了两次。 为了验证上述结论,我们更改一下服务端以及自定义解码器,其余的代码不修改: package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } } package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder.class); /** * * @param ctx 上下文对象 * @param in 网络IO传输过来的数据,存储到ByteBuf类型的in中 * @param out 解码处理完后,把每一个"Message"都存储到out这一集合中,便于后续Netty遍历该out集合进行执行pipeline流水线的Handler操作 * Netty是以消息Message为单位进行处理数据的,有多少Message,就执行多少次pipeline * ----> * 如果字节数不超过滑动窗口,socket缓冲区,ByteBuf缓冲区,客户端只发一次数据即可,为什么服务端能划分出多个Message呢? * 原因很简单:每调用一次decode进行处理ByteBuf,那么就会封装成一个Message。 * 如果服务端一次没有处理完ByteBuf,那么会进行第二次调用decode方法的处理,则第二次处理ByteBuf,则又会生成一个新的Message * 以此类推,直到ByteBuf中的数据都处理完。 * 调用n次decode方法,处理ByteBuf n次,存储n个Message到out集合中 * ----> * 啥时候意味着ByteBuf中的数据都处理完? * 其实还是指针的移动,思考一下之前NIO的各种指针,当读指针到达limit指针边界后就意味着ByteBuf处理完毕 * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L // long reciveLong = in.readLong(); // out.add(reciveLong); //如果一次读取16字节,是不是可以一次读完ByteBuf,那么就只会添加一个Message到out集合中,那么只会调用一次pipeline流水线 out.add(in.readBytes(16)); } } } 测试输出: 客户端:客户端还是只发了一次数据就完事了 服务端: 接收到客户端一次发送的数据后存储到ByteBuf中,但是会多次解析读取该ByteBuf,多次调用decode方法,把每一次decode解码的Message存储到out集合中,把out交给netty,之后会遍历out集合,让每一个Message都对应调用一遍pipeline流水线。pipeline流水线的Handler拿到的数据就是out集合中解码后的数据 ,然后我们就可以根据该解码后的数据去做一系列的操作了。 为什么只执行一次? 因为ByteBuf被一次读取完了,哈哈哈,那么就肯定只执行一次decode方法了。所以out集合中只会添加一个Message,那么只会调用一遍pipeline流水线的Handler。 25.2 自定义编解码器的总结和补充 1.自定义编码器 继承 MessageToByteEncoder,自定义实现其encode方法的逻辑 2.自定义解码器 继承 ByteToMessageDecoder,自定义实现其decode方法的逻辑 其实还有一种设计方法,我们前面说过存在一个集合体,拥有编解码器的能力的一个类。 ByteToMessageCodec,于是我们可以继承这个类,实现两个方法一个是decode一个是encode。 这种方式就可以替代上述两种自定义编码器和解码器,操作步骤如下: MyLongCodec类的设计 package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyLongCodec extends ByteToMessageCodec { private static final Logger log = LoggerFactory.getLogger(MyLongCodec.class); @Override protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception { log.info("MyLong2ByteEncoder.encode start ~~~ ") ; if (msg == null) { return; } String[] msgs = msg.split("-"); for (String message : msgs) { long longMsg = Long.parseLong(message); //每一个long类型的数据都在ByteBuf中占用8字节的大小空间 out.writeLong(longMsg); } } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L // long reciveLong = in.readLong(); // out.add(reciveLong); //如果一次读取16字节,是不是可以一次读完ByteBuf,那么就只会添加一个Message到out集合中,那么只会调用一次pipeline流水线 out.add(in.readBytes(16)); } } } 客户端与服务端的设计如下 package com.messi.netty_core_02.netty10; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //日志输出的编码器 pipeline.addLast(new LoggingHandler()); //我们自定义的编码器 // pipeline.addLast(new MyLong2ByteEncoder()); pipeline.addLast(new MyLongCodec()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush("10-20"); group.shutdownGracefully(); } } package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); // pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(new MyLongCodec()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } } 测试输出: 客户端: 服务端: 测试通过,成功。 其实还有一种解码器ReplayingDecoder 这个解码器是netty封装的,这个解码器比较强大,我们在使用这个解码器的时候是不需要做一些安全性校验的。比如我们之前的解码器,做了一个长度判断,如下伪代码所示: // 获得byteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); // 我们客户端写的数据是long占八字节,所以这里判断接收到的数据长度是不是够 if(readableBytes >= 8){ 这个检验是因为我们担心服务端接收到的长度不够,丢失数据精度或者是异常抛出等等。如果不做长度判断,那么这一次读取错了,以后只会越读越错误。 甚至更有可能:接收到的根本不是这个类型的数据!比如说发送过来的是:两个整型或8个Byte类型,这一共也是8字节,所以肯定会有问题。 如果出现以上问题,你读错误一次,就算你发现该错误或抛出异常,也无法挽回,为什么无法挽回呢?因为你读取ByteBuf的数据是会改变读指针的,一旦改变指针,你就无法再往回读了。 所以这里我们可以使用到之前NIO总结的一种回滚指针的解决思路,当然netty中也有对应的回滚指针解决方案,修改代码如下所示: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder2 extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); int readableBytes = in.readableBytes(); if (readableBytes >= 8) { //标记读指针此时的位置,错误时回滚到该位置 in.markReaderIndex(); try { //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } catch (Exception e) { //发生异常时,回滚到标记位置 in.resetReaderIndex(); } } } } 但是你要是继承实现了ReplayingDecoder,这个解码器,那你那些安全校验,全部取消,变为如下这样。 代码如下: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ReplayingDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder3 extends ReplayingDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } } 原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。 # 所以你的netty编程,要考虑如下方面: 1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。 2. ByteBuf是不是合理释放了。 26.自定义通信协议 26.1 关于通信协议的关注点 网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。 说白了就是客户端与服务端传输的格式,样式 在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。 而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子: 版本1: 我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"} 登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。 于是我们需要增加一个数据长度 版本2: 协议正文,或者叫做协议体,消息正文依然是账号密码 {"name":"xxx","password":"123456"} 正文长度:告诉服务端你一次读取多少数据,避免半包粘包 魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。 协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作 指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 26.2 自定义通信协议的格式 json序列化方式: 在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。 大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。 在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。 json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。 但是一般在高并发开发中,并且如果是抛开SpringCloud-Web那一套Http协议,在netty原生开发时,我们可以自定义协议自定义序列化方式的话,我们有如下序列化方式的选择建议: 头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储 消息正文:json/java序列化/protobuf 为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制? 答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。 为什么要使用java序列化或protobuf序列化取代json? json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判? 并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化? 补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。 由于序列化方式的变化选择,我们得出一种最终方案 使用netty做自定义协议时: 头信息: 客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制 消息正文: 客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据 由于序列化方式选择的不确定性,所以客户端发消息的时候要多加一个"序列化的方式"字段 该字段是用来标识选择的序列化方式是啥? 于是协议的内容就变成如下这样: 协议正文(或叫做协议体): 消息正文依然是账号密码,{"name":"xxx","password","123456"} 正文长度: 告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生 魔数: 每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。 协议版本号: 协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作 指令类型: 业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 序列化的方式: 比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式 26.3 编解码 在设计好了编码格式之后,我们就可以来考虑编解码了。 在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。 编码过程如下 编写消息类Message package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 客户端自定义编码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } } 客户端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } } 服务端自定义解码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
客户端输出:
由于自定义编码中去除了分隔符"-",所以只发送16字节的数据给服务端。注意:是一次性发送16字节的数据给服务端
服务端输出:
如下图所示,服务端自定义解码器调用了两次,为什么?
因为在自定义解码器的逻辑中,一次只处理了ByteBuf中8字节的数据大小,所以一次处理不完ByteBuf,所以会多次处理,多次处理会多次调用decode方法,会多次加入"Message"到out这一List集合中。由于out这一集合中有多个Message,所以pipeline流水线的Handler会执行多次。
总结:
首先明确一点,客户端对于这两个long类型的数字,10和20,他是只发送了一次的,因为我们首先看到这个数据的结构,其次日志只输出了一次。
再次我们来看服务端日志,数据是处理了两次的,因为输出了两次,解码器处理了两次。那么这是为
啥。
1、首先不是半包黏包,因为我们的缓冲区不至于连两个long都拿不到。
2、因为是两个消息,我们的数据在被解码器处理之后客户端那里其实是把数据处理位两个long发过来
的,服务端这里解码处理其实得到两个消息message,添加到out集合里面是两个消息。然后就处理了两次,这里有个问题就是,当你的ByteBuf的数据一次没处理完,那就会继续调用decode方法,进行再次处理,因为我们的数据是16字节,第一次值处理了八个字节,因为我们读取的就是一个readLong,long就是读取读写指针的前八个字节,所以处理了两次。
package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } }
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder.class); /** * * @param ctx 上下文对象 * @param in 网络IO传输过来的数据,存储到ByteBuf类型的in中 * @param out 解码处理完后,把每一个"Message"都存储到out这一集合中,便于后续Netty遍历该out集合进行执行pipeline流水线的Handler操作 * Netty是以消息Message为单位进行处理数据的,有多少Message,就执行多少次pipeline * ----> * 如果字节数不超过滑动窗口,socket缓冲区,ByteBuf缓冲区,客户端只发一次数据即可,为什么服务端能划分出多个Message呢? * 原因很简单:每调用一次decode进行处理ByteBuf,那么就会封装成一个Message。 * 如果服务端一次没有处理完ByteBuf,那么会进行第二次调用decode方法的处理,则第二次处理ByteBuf,则又会生成一个新的Message * 以此类推,直到ByteBuf中的数据都处理完。 * 调用n次decode方法,处理ByteBuf n次,存储n个Message到out集合中 * ----> * 啥时候意味着ByteBuf中的数据都处理完? * 其实还是指针的移动,思考一下之前NIO的各种指针,当读指针到达limit指针边界后就意味着ByteBuf处理完毕 * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L // long reciveLong = in.readLong(); // out.add(reciveLong); //如果一次读取16字节,是不是可以一次读完ByteBuf,那么就只会添加一个Message到out集合中,那么只会调用一次pipeline流水线 out.add(in.readBytes(16)); } } } 测试输出: 客户端:客户端还是只发了一次数据就完事了 服务端: 接收到客户端一次发送的数据后存储到ByteBuf中,但是会多次解析读取该ByteBuf,多次调用decode方法,把每一次decode解码的Message存储到out集合中,把out交给netty,之后会遍历out集合,让每一个Message都对应调用一遍pipeline流水线。pipeline流水线的Handler拿到的数据就是out集合中解码后的数据 ,然后我们就可以根据该解码后的数据去做一系列的操作了。 为什么只执行一次? 因为ByteBuf被一次读取完了,哈哈哈,那么就肯定只执行一次decode方法了。所以out集合中只会添加一个Message,那么只会调用一遍pipeline流水线的Handler。 25.2 自定义编解码器的总结和补充 1.自定义编码器 继承 MessageToByteEncoder,自定义实现其encode方法的逻辑 2.自定义解码器 继承 ByteToMessageDecoder,自定义实现其decode方法的逻辑 其实还有一种设计方法,我们前面说过存在一个集合体,拥有编解码器的能力的一个类。 ByteToMessageCodec,于是我们可以继承这个类,实现两个方法一个是decode一个是encode。 这种方式就可以替代上述两种自定义编码器和解码器,操作步骤如下: MyLongCodec类的设计 package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyLongCodec extends ByteToMessageCodec { private static final Logger log = LoggerFactory.getLogger(MyLongCodec.class); @Override protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception { log.info("MyLong2ByteEncoder.encode start ~~~ ") ; if (msg == null) { return; } String[] msgs = msg.split("-"); for (String message : msgs) { long longMsg = Long.parseLong(message); //每一个long类型的数据都在ByteBuf中占用8字节的大小空间 out.writeLong(longMsg); } } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L // long reciveLong = in.readLong(); // out.add(reciveLong); //如果一次读取16字节,是不是可以一次读完ByteBuf,那么就只会添加一个Message到out集合中,那么只会调用一次pipeline流水线 out.add(in.readBytes(16)); } } } 客户端与服务端的设计如下 package com.messi.netty_core_02.netty10; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //日志输出的编码器 pipeline.addLast(new LoggingHandler()); //我们自定义的编码器 // pipeline.addLast(new MyLong2ByteEncoder()); pipeline.addLast(new MyLongCodec()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush("10-20"); group.shutdownGracefully(); } } package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); // pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(new MyLongCodec()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } } 测试输出: 客户端: 服务端: 测试通过,成功。 其实还有一种解码器ReplayingDecoder 这个解码器是netty封装的,这个解码器比较强大,我们在使用这个解码器的时候是不需要做一些安全性校验的。比如我们之前的解码器,做了一个长度判断,如下伪代码所示: // 获得byteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); // 我们客户端写的数据是long占八字节,所以这里判断接收到的数据长度是不是够 if(readableBytes >= 8){ 这个检验是因为我们担心服务端接收到的长度不够,丢失数据精度或者是异常抛出等等。如果不做长度判断,那么这一次读取错了,以后只会越读越错误。 甚至更有可能:接收到的根本不是这个类型的数据!比如说发送过来的是:两个整型或8个Byte类型,这一共也是8字节,所以肯定会有问题。 如果出现以上问题,你读错误一次,就算你发现该错误或抛出异常,也无法挽回,为什么无法挽回呢?因为你读取ByteBuf的数据是会改变读指针的,一旦改变指针,你就无法再往回读了。 所以这里我们可以使用到之前NIO总结的一种回滚指针的解决思路,当然netty中也有对应的回滚指针解决方案,修改代码如下所示: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder2 extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); int readableBytes = in.readableBytes(); if (readableBytes >= 8) { //标记读指针此时的位置,错误时回滚到该位置 in.markReaderIndex(); try { //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } catch (Exception e) { //发生异常时,回滚到标记位置 in.resetReaderIndex(); } } } } 但是你要是继承实现了ReplayingDecoder,这个解码器,那你那些安全校验,全部取消,变为如下这样。 代码如下: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ReplayingDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder3 extends ReplayingDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } } 原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。 # 所以你的netty编程,要考虑如下方面: 1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。 2. ByteBuf是不是合理释放了。 26.自定义通信协议 26.1 关于通信协议的关注点 网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。 说白了就是客户端与服务端传输的格式,样式 在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。 而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子: 版本1: 我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"} 登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。 于是我们需要增加一个数据长度 版本2: 协议正文,或者叫做协议体,消息正文依然是账号密码 {"name":"xxx","password":"123456"} 正文长度:告诉服务端你一次读取多少数据,避免半包粘包 魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。 协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作 指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 26.2 自定义通信协议的格式 json序列化方式: 在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。 大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。 在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。 json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。 但是一般在高并发开发中,并且如果是抛开SpringCloud-Web那一套Http协议,在netty原生开发时,我们可以自定义协议自定义序列化方式的话,我们有如下序列化方式的选择建议: 头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储 消息正文:json/java序列化/protobuf 为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制? 答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。 为什么要使用java序列化或protobuf序列化取代json? json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判? 并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化? 补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。 由于序列化方式的变化选择,我们得出一种最终方案 使用netty做自定义协议时: 头信息: 客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制 消息正文: 客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据 由于序列化方式选择的不确定性,所以客户端发消息的时候要多加一个"序列化的方式"字段 该字段是用来标识选择的序列化方式是啥? 于是协议的内容就变成如下这样: 协议正文(或叫做协议体): 消息正文依然是账号密码,{"name":"xxx","password","123456"} 正文长度: 告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生 魔数: 每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。 协议版本号: 协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作 指令类型: 业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 序列化的方式: 比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式 26.3 编解码 在设计好了编码格式之后,我们就可以来考虑编解码了。 在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。 编码过程如下 编写消息类Message package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 客户端自定义编码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } } 客户端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } } 服务端自定义解码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
测试输出:
客户端:客户端还是只发了一次数据就完事了
服务端:
接收到客户端一次发送的数据后存储到ByteBuf中,但是会多次解析读取该ByteBuf,多次调用decode方法,把每一次decode解码的Message存储到out集合中,把out交给netty,之后会遍历out集合,让每一个Message都对应调用一遍pipeline流水线。pipeline流水线的Handler拿到的数据就是out集合中解码后的数据
,然后我们就可以根据该解码后的数据去做一系列的操作了。
为什么只执行一次?
因为ByteBuf被一次读取完了,哈哈哈,那么就肯定只执行一次decode方法了。所以out集合中只会添加一个Message,那么只会调用一遍pipeline流水线的Handler。
1.自定义编码器
继承 MessageToByteEncoder,自定义实现其encode方法的逻辑
2.自定义解码器
继承 ByteToMessageDecoder,自定义实现其decode方法的逻辑
其实还有一种设计方法,我们前面说过存在一个集合体,拥有编解码器的能力的一个类。
ByteToMessageCodec,于是我们可以继承这个类,实现两个方法一个是decode一个是encode。
这种方式就可以替代上述两种自定义编码器和解码器,操作步骤如下:
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyLongCodec extends ByteToMessageCodec { private static final Logger log = LoggerFactory.getLogger(MyLongCodec.class); @Override protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception { log.info("MyLong2ByteEncoder.encode start ~~~ ") ; if (msg == null) { return; } String[] msgs = msg.split("-"); for (String message : msgs) { long longMsg = Long.parseLong(message); //每一个long类型的数据都在ByteBuf中占用8字节的大小空间 out.writeLong(longMsg); } } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder解码器start~~~"); //获得ByteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); //如果客户端写的数据是long占8字节,这里是判断长度字节够不够,如果不够,那么说明有问题 if (readableBytes >= 8) { //发送的是"10-20",第一次拿到的是10L(long类型),第二次是20L // long reciveLong = in.readLong(); // out.add(reciveLong); //如果一次读取16字节,是不是可以一次读完ByteBuf,那么就只会添加一个Message到out集合中,那么只会调用一次pipeline流水线 out.add(in.readBytes(16)); } } } 客户端与服务端的设计如下 package com.messi.netty_core_02.netty10; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //日志输出的编码器 pipeline.addLast(new LoggingHandler()); //我们自定义的编码器 // pipeline.addLast(new MyLong2ByteEncoder()); pipeline.addLast(new MyLongCodec()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush("10-20"); group.shutdownGracefully(); } } package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); // pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(new MyLongCodec()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } } 测试输出: 客户端: 服务端: 测试通过,成功。 其实还有一种解码器ReplayingDecoder 这个解码器是netty封装的,这个解码器比较强大,我们在使用这个解码器的时候是不需要做一些安全性校验的。比如我们之前的解码器,做了一个长度判断,如下伪代码所示: // 获得byteBuf中读写指针之间可读的数据长度 int readableBytes = in.readableBytes(); // 我们客户端写的数据是long占八字节,所以这里判断接收到的数据长度是不是够 if(readableBytes >= 8){ 这个检验是因为我们担心服务端接收到的长度不够,丢失数据精度或者是异常抛出等等。如果不做长度判断,那么这一次读取错了,以后只会越读越错误。 甚至更有可能:接收到的根本不是这个类型的数据!比如说发送过来的是:两个整型或8个Byte类型,这一共也是8字节,所以肯定会有问题。 如果出现以上问题,你读错误一次,就算你发现该错误或抛出异常,也无法挽回,为什么无法挽回呢?因为你读取ByteBuf的数据是会改变读指针的,一旦改变指针,你就无法再往回读了。 所以这里我们可以使用到之前NIO总结的一种回滚指针的解决思路,当然netty中也有对应的回滚指针解决方案,修改代码如下所示: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder2 extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); int readableBytes = in.readableBytes(); if (readableBytes >= 8) { //标记读指针此时的位置,错误时回滚到该位置 in.markReaderIndex(); try { //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } catch (Exception e) { //发生异常时,回滚到标记位置 in.resetReaderIndex(); } } } } 但是你要是继承实现了ReplayingDecoder,这个解码器,那你那些安全校验,全部取消,变为如下这样。 代码如下: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ReplayingDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder3 extends ReplayingDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } } 原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。 # 所以你的netty编程,要考虑如下方面: 1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。 2. ByteBuf是不是合理释放了。 26.自定义通信协议 26.1 关于通信协议的关注点 网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。 说白了就是客户端与服务端传输的格式,样式 在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。 而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子: 版本1: 我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"} 登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。 于是我们需要增加一个数据长度 版本2: 协议正文,或者叫做协议体,消息正文依然是账号密码 {"name":"xxx","password":"123456"} 正文长度:告诉服务端你一次读取多少数据,避免半包粘包 魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。 协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作 指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 26.2 自定义通信协议的格式 json序列化方式: 在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。 大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。 在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。 json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。 但是一般在高并发开发中,并且如果是抛开SpringCloud-Web那一套Http协议,在netty原生开发时,我们可以自定义协议自定义序列化方式的话,我们有如下序列化方式的选择建议: 头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储 消息正文:json/java序列化/protobuf 为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制? 答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。 为什么要使用java序列化或protobuf序列化取代json? json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判? 并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化? 补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。 由于序列化方式的变化选择,我们得出一种最终方案 使用netty做自定义协议时: 头信息: 客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制 消息正文: 客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据 由于序列化方式选择的不确定性,所以客户端发消息的时候要多加一个"序列化的方式"字段 该字段是用来标识选择的序列化方式是啥? 于是协议的内容就变成如下这样: 协议正文(或叫做协议体): 消息正文依然是账号密码,{"name":"xxx","password","123456"} 正文长度: 告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生 魔数: 每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。 协议版本号: 协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作 指令类型: 业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 序列化的方式: 比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式 26.3 编解码 在设计好了编码格式之后,我们就可以来考虑编解码了。 在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。 编码过程如下 编写消息类Message package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 客户端自定义编码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } } 客户端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } } 服务端自定义解码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
package com.messi.netty_core_02.netty10; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //日志输出的编码器 pipeline.addLast(new LoggingHandler()); //我们自定义的编码器 // pipeline.addLast(new MyLong2ByteEncoder()); pipeline.addLast(new MyLongCodec()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush("10-20"); group.shutdownGracefully(); } }
package com.messi.netty_core_02.netty10; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); // pipeline.addLast(new MyByte2LongDecoder()); pipeline.addLast(new MyLongCodec()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter(){ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // if(msg instanceof Long) { // Long data = (Long) msg; // log.info("得到的客户端输入为:{}",data) ; // } //验证读取n次ByteBuf,调用n次decode方法,对应有n个Message,会添加n个Message到out集合 //netty拿到该out集合,会遍历并且让每一个Message都执行一遍pipeline流水线 log.info("得到的客户端输入为:{}",msg.toString()); } }); } }); serverBootstrap.bind(8000); } }
客户端:
测试通过,成功。
其实还有一种解码器ReplayingDecoder
这个解码器是netty封装的,这个解码器比较强大,我们在使用这个解码器的时候是不需要做一些安全性校验的。比如我们之前的解码器,做了一个长度判断,如下伪代码所示:
// 获得byteBuf中读写指针之间可读的数据长度
int readableBytes = in.readableBytes();
// 我们客户端写的数据是long占八字节,所以这里判断接收到的数据长度是不是够
if(readableBytes >= 8){
这个检验是因为我们担心服务端接收到的长度不够,丢失数据精度或者是异常抛出等等。如果不做长度判断,那么这一次读取错了,以后只会越读越错误。
甚至更有可能:接收到的根本不是这个类型的数据!比如说发送过来的是:两个整型或8个Byte类型,这一共也是8字节,所以肯定会有问题。
如果出现以上问题,你读错误一次,就算你发现该错误或抛出异常,也无法挽回,为什么无法挽回呢?因为你读取ByteBuf的数据是会改变读指针的,一旦改变指针,你就无法再往回读了。
所以这里我们可以使用到之前NIO总结的一种回滚指针的解决思路,当然netty中也有对应的回滚指针解决方案,修改代码如下所示:
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder2 extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); int readableBytes = in.readableBytes(); if (readableBytes >= 8) { //标记读指针此时的位置,错误时回滚到该位置 in.markReaderIndex(); try { //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } catch (Exception e) { //发生异常时,回滚到标记位置 in.resetReaderIndex(); } } } } 但是你要是继承实现了ReplayingDecoder,这个解码器,那你那些安全校验,全部取消,变为如下这样。 代码如下: package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ReplayingDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder3 extends ReplayingDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } } 原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。 # 所以你的netty编程,要考虑如下方面: 1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。 2. ByteBuf是不是合理释放了。 26.自定义通信协议 26.1 关于通信协议的关注点 网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。 说白了就是客户端与服务端传输的格式,样式 在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。 而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子: 版本1: 我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"} 登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。 于是我们需要增加一个数据长度 版本2: 协议正文,或者叫做协议体,消息正文依然是账号密码 {"name":"xxx","password":"123456"} 正文长度:告诉服务端你一次读取多少数据,避免半包粘包 魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。 协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作 指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 26.2 自定义通信协议的格式 json序列化方式: 在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。 大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。 在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。 json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。 但是一般在高并发开发中,并且如果是抛开SpringCloud-Web那一套Http协议,在netty原生开发时,我们可以自定义协议自定义序列化方式的话,我们有如下序列化方式的选择建议: 头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储 消息正文:json/java序列化/protobuf 为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制? 答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。 为什么要使用java序列化或protobuf序列化取代json? json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判? 并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化? 补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。 由于序列化方式的变化选择,我们得出一种最终方案 使用netty做自定义协议时: 头信息: 客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制 消息正文: 客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据 由于序列化方式选择的不确定性,所以客户端发消息的时候要多加一个"序列化的方式"字段 该字段是用来标识选择的序列化方式是啥? 于是协议的内容就变成如下这样: 协议正文(或叫做协议体): 消息正文依然是账号密码,{"name":"xxx","password","123456"} 正文长度: 告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生 魔数: 每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。 协议版本号: 协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作 指令类型: 业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 序列化的方式: 比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式 26.3 编解码 在设计好了编码格式之后,我们就可以来考虑编解码了。 在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。 编码过程如下 编写消息类Message package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 客户端自定义编码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } } 客户端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } } 服务端自定义解码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
但是你要是继承实现了ReplayingDecoder,这个解码器,那你那些安全校验,全部取消,变为如下这样。
代码如下:
package com.messi.netty_core_02.netty10; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ReplayingDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public class MyByte2LongDecoder3 extends ReplayingDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2LongDecoder2.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2LongDecoder2解码器执行"); //发过来的是"10-20",第一次读取的是20L,第二次读取的是20L long reciveLong = in.readLong(); out.add(reciveLong); } } 原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。 # 所以你的netty编程,要考虑如下方面: 1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。 2. ByteBuf是不是合理释放了。 26.自定义通信协议 26.1 关于通信协议的关注点 网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。 说白了就是客户端与服务端传输的格式,样式 在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。 而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子: 版本1: 我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"} 登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。 于是我们需要增加一个数据长度 版本2: 协议正文,或者叫做协议体,消息正文依然是账号密码 {"name":"xxx","password":"123456"} 正文长度:告诉服务端你一次读取多少数据,避免半包粘包 魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。 协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作 指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 26.2 自定义通信协议的格式 json序列化方式: 在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。 大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。 在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。 json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。 但是一般在高并发开发中,并且如果是抛开SpringCloud-Web那一套Http协议,在netty原生开发时,我们可以自定义协议自定义序列化方式的话,我们有如下序列化方式的选择建议: 头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储 消息正文:json/java序列化/protobuf 为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制? 答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。 为什么要使用java序列化或protobuf序列化取代json? json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判? 并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化? 补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。 由于序列化方式的变化选择,我们得出一种最终方案 使用netty做自定义协议时: 头信息: 客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制 消息正文: 客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据 由于序列化方式选择的不确定性,所以客户端发消息的时候要多加一个"序列化的方式"字段 该字段是用来标识选择的序列化方式是啥? 于是协议的内容就变成如下这样: 协议正文(或叫做协议体): 消息正文依然是账号密码,{"name":"xxx","password","123456"} 正文长度: 告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生 魔数: 每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。 协议版本号: 协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作 指令类型: 业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务 序列化的方式: 比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式 26.3 编解码 在设计好了编码格式之后,我们就可以来考虑编解码了。 在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。 编码过程如下 编写消息类Message package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 客户端自定义编码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } } 客户端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } } 服务端自定义解码器 package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
原理很简单:底层帮你处理了所有的安全问题,重置了ByteBuf,传递给你的是一个安全的处理过的ByteBuf,不管你什么异常什么问题,都会给你解决。
# 所以你的netty编程,要考虑如下方面:
1. ByteBuf的读写指针要考虑是不是正确,错了是不是能回滚。
2. ByteBuf是不是合理释放了。
网络传输有很多协议了,像HTTP这种都是应用层协议,但是有时候我们在做网络通信的时候,需要自己定义一些协议,我们能够自定义出来的协议都是属于上层(应用层)的协议,因为都是基于底层封装好的TCP/UDP网络协议栈的基础协议。我们自定义出一些协议,来约束双方的接收和发送,这种时候需要我们来自定义通信协议,也就是消息的格式。
说白了就是客户端与服务端传输的格式,样式
在这个数据传递的过程中,你需要注意的就是除了基本数据的定义格式,还需要注意传递数据的长度,不然会出现半包粘包问题。
而且除了你的业务数据,还需要一些元数据(如:数据长度等),这些都要考虑,来举一个登录的例子:
版本1:
我们设计一个消息结构,就是json格式的内容:{"name":"xxx","password":"xxx"}
登录信息,无外乎就是账号密码。我们这么设计没毛病,但是没意义,首先没有数据长度,会出现半包粘包问题。
于是我们需要增加一个数据长度
版本2:
协议正文,或者叫做协议体,消息正文依然是账号密码
{"name":"xxx","password":"123456"}
正文长度:告诉服务端你一次读取多少数据,避免半包粘包
魔数:每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就需要携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数一律认为不合规,就丢弃掉。这是一个牌号,校验使用的,不然你随意一个系统知道ip,端口号就都能给我发数据,这不就乱了。
协议版本号:协议可能升级,告诉服务端当前协议是哪一个版本,服务端就采用对应的逻辑操作
指令类型:业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用的是哪种操作,http设计的时候实际上不需要这个,因为它没有什么业务操作,就是收发数据,然后就没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务
json序列化方式:
在有了上面的考虑点,我们现在可以定义一个我们消息的格式了,在定义格式之前,我们先考虑以什么形式构建,我们最熟悉的格式就是json,用json格式来组织起来上面的注意点。我们来看一个现在的结构。
大体上我们在客户端组织的消息格式就是这样的,然后我们经过封装为ByteBuf发送出去。
在服务端,用new JsonObjectDecode完成解码,进行后续的handler业务处理。
json的设计格式还行,json的字段本身就是能随便加的,但是这个格式有问题,就是他的长度太大了,因为我们这个json格式他全是字符串,在传输过程中不如二进制,或者其他的编码格式更加精简和体量小。但是json也有他的好处,就是可读性强,内部处理很方便。所以我们要是非要用json,建议除了消息体其他都用二进制。
头信息(头信息是指除了消息正文content这一字段外的其他字段数据):一般都使用二进制byte直接存储
消息正文:json/java序列化/protobuf
为什么头信息不也直接使用java序列化或protobuf呢?java序列化或protobuf不也都是序列化成二进制?
答案其实很简单,直接写入二进制byte不带有对存储数据的额外描述信息。java序列化或protobuf把数据序列化成二进制,但是会带有许多额外的描述信息来保证可以反序列化成功,相比直接写入byte 占用的空间肯定要大很多。
为什么要使用java序列化或protobuf序列化取代json?
json序列化后的数据格式带有太多无用的符号,并且json序列化后的是字符串,所有的数据都是字符格式,所谓字符格式,一个普通字符占2字节,一个汉字占用3字节。而你protobuf或java序列化后的数据是二进制格式,8个二进制等于1字节,高下立判?
并且序列化后需要进行统一编码成二进制字节流存储到ByteBuf或其他应用缓冲区中,便于后续发给socket内核缓冲区。如果采用json方式,字符编码成二进制字节格式,又是很大的性能消耗。但是如果采用java序列化或protobuf方式,本身序列化后就成为了二进制字节格式,不存在字符解析的性能消耗。是不是也是很大的性能优化?
补充:但是一般来说,我们使用的protobuf方式,而不采用java默认的序列化方式,因为protobuf性能更高。
使用netty做自定义协议时:
头信息:
客户端编码使用二进制直接写入,服务端收到消息后解码直接读取二进制
消息正文:
客户端使用protobuf方式序列化原生消息成二进制数据,服务端使用protobuf反序列化二进制数据成原生消息数据
该字段是用来标识选择的序列化方式是啥?
于是协议的内容就变成如下这样:
协议正文(或叫做协议体):
消息正文依然是账号密码,{"name":"xxx","password","123456"}
正文长度:
告诉服务端:我发的数据长度。所以服务端知道一次读取多少,避免半包粘包问题的发生
魔数:
每个系统之间的一个读取标识,比如用来标识我们是一个集团或系统的,你就携带一个CAFEBABY过来,我就知道你的消息是我们系统的了,不携带这个魔数则一律认为该请求消息是不合理的,就丢弃掉,这是一个牌号,校验使用的。不然你随意一个系统要是知道服务端的ip,端口的话,那岂不是都能给服务端发数据,那么不是乱了。
协议版本号:
协议可能升级,告诉服务端当前协议是哪一个版本,服务端采用对应的逻辑操作
指令类型:
业务操作的编号,比如1是登录,2是注册,3是注销等等,告诉服务端具体使用哪种操作。http设计的时候实际上不需要这个,因为他没什么业务操作,就是收发数据,没了。但是你使用http协议想要做类型区别的话,那么你要做类型区别那就在请求里面加你的参数,然后服务端后台去判断。比如你url里面是delete那么就走去delete删除业务
序列化的方式:
比如:1代表json 2代表protobuf 3代表Hessian 4代表java默认的序列化方式
在设计好了编码格式之后,我们就可以来考虑编解码了。
在这个过程中,我们的数据被封装成ByteBuf就发送出去了,但是思考一个问题,作为客户端你是写业务代码的,你发出去的应该就是一个纯净的对象,你不能在对象数据的属性中加上一个魔数,版本号什么的。你需要把对象数据之外的元数据加在对象外面并且协同对象一起发送过去,这个封装的过程我们就需要交给客户端对应的编码器去做。ofcourse,解析这个封装好的消息数据的过程肯定是交给接收消息的服务端解码器去做,服务端解析得到消息正文以及元数据,便于做之后的一系列业务操作。
编码过程如下
package com.messi.netty_core_02.netty11; import java.io.Serializable; public class Message implements Serializable { private String username; private String password; public Message() { } public Message(String username,String password) { this.username = username ; this.password = password ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Message{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; public class MyMessage2ByteEncoder extends MessageToByteEncoder { private static final Logger log = LoggerFactory.getLogger(MyMessage2ByteEncoder.class); @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { log.info("MyMessage2ByteEncoder.encode"); //1.魔数 8字节 out.writeBytes("leomessi".getBytes()); //2.版本 1字节 out.writeByte(1); //3.序列化方式 1字节 1代表json 2代表protobu 3代表hessian out.writeByte(1); //4.指令功能 1字节 1代表登录 2代表注册 out.writeByte(1); //5.正文长度 4字节 使用int整型标识 ObjectMapper objectMapper = new ObjectMapper(); String jsonContent = objectMapper.writeValueAsString(msg); out.writeInt(jsonContent.length()); //6.正文,直接写char序列 out.writeCharSequence(jsonContent, Charset.defaultCharset()); } }
package com.messi.netty_core_02.netty11; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import java.net.InetSocketAddress; public class MyNettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group); bootstrap.handler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyMessage2ByteEncoder()); } }); Channel channel = bootstrap.connect(new InetSocketAddress(8000)).sync().channel(); channel.writeAndFlush(new Message("leo","101010")); System.out.println("MyNettyClient.main"); group.shutdownGracefully(); } }
package com.messi.netty_core_02.netty11; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; import java.util.List; public class MyByte2MessageDecoder extends ByteToMessageDecoder { private static final Logger log = LoggerFactory.getLogger(MyByte2MessageDecoder.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { log.info("MyByte2MessageDecoder.decode"); //魔数 ByteBuf magic = in.readBytes(8); log.info("魔数为:{}",magic); //协议版本号 byte version = in.readByte(); log.info("协议版本号为:{}",version); //序列化方式 byte serializableType = in.readByte(); log.info("序列化方式为:{}",serializableType) ; //指令功能 byte funcNo = in.readByte(); log.info("指令功能为:{}",funcNo) ; //正文长度 int contentLength = in.readInt(); log.info("正文长度为:{}",contentLength) ; Message message = null ; if (serializableType == 1 ){ //说明序列化方式为json,此时服务端就要使用json反序列化方式进行反序列化 ObjectMapper objectMapper = new ObjectMapper(); message = objectMapper.readValue(in.readCharSequence(contentLength, Charset.defaultCharset()).toString(),Message.class); } out.add(message); } } 服务端 package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } } 输出 客户端输出: 服务端输出: 补充 总结: 你可能感兴趣的:(Netty应用,java,后端,netty) 【Java】代理模式 非 白 代理模式java开发语言 代理模式代理模式是指给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问代理模式是一种结构型设计模式背景如果不采用代理,对一个类的多个方法进行监控时,重复的代码总是重复出现,不但破坏了原方法,如果要实现多个监控,将会对代码造成大量冗余。同时,还导致业务代码,与非业务的监控代码掺杂在一起,不利于扩展和维护。代理类在无限制膨胀,就需要无限的修改业务代码。而采用代理后,原方法不需要做任何改动,操 国外7个最佳大语言模型 (LLM) API推荐 程序员后端 大型语言模型(LLM)API将彻底改变我们处理语言的方式。在深度学习和机器学习算法的支持下,LLMAPI提供了前所未有的自然语言理解能力。通过利用这些新的API,开发人员现在可以创建能够以前所未有的方式理解和响应书面文本的应用程序。下面,我们将比较从Bard到ChatGPT、PaLM等市场上顶级LLMAPI。我们还将探讨整合这些LLM的潜在用例,并考虑其对语言处理的影响。什么是大语言模型(LLM) 责任链模式原理详解和源码实例以及Spring AOP拦截器链的执行源码如何使用责任链模式? 一个儒雅随和的男子 spring设计模式责任链模式springjava 前言 本文首先介绍了责任链的基本原理,并附带一个例子说明责任链模式,确保能够理解责任链的前提下,在进行SpringAOP执行责任链的源码分析。责任链模式允许将多个处理对象连接成链,请求沿着链传递,直到被处理或结束。每个处理者可以选择处理请求或传递给下一个。 SpringAOP的拦截器链,拦截器或者过滤器链,都是典型的责任链应用。比如,当一个方法被调用时,多个拦截器按顺序执行,每个拦截器可以决定 技术分享:MyBatis SQL 日志解析脚本 £漫步 云端彡 运维趣分享sqljavamybatis日志解析 技术分享:MyBatisSQL日志解析脚本1.脚本功能概述2.实现细节2.1HTML结构2.2JavaScript逻辑3.脚本代码4.使用方法4.1示例5.总结在日常开发中,使用MyBatis作为持久层框架时,我们经常需要查看SQL日志以调试和优化查询。然而,MyBatis的日志输出通常包含占位符和参数信息,这使得直接执行这些SQL语句变得困难。为了解决这个问题,我们开发了一个简单的HTML和Ja SMT贴片生产的发展趋势与技术创新解析 安德胜SMT贴片 人工智能 内容概要SMT贴片生产作为现代电子制造的重要组成部分,其发展一直颇具前景与活力。当前,行业内的技术进步与市场需求的快速变化使得SMT贴片生产面临新的机遇与挑战。尤其是在自动化技术方面,许多企业逐步引入更加智能化的设备,从而提升生产效率并降低人为错误。这不仅能够缩短生产周期,还能提高产品的一致性和可靠性。另外,材料科技的进步也促进了SMT贴片生产的变革。新型材料的应用,例如高电导率材料和环保型焊料, C语言-回调函数的应用 woainizhongguo. C/C++c语言 什么是回调函数回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。工作机制⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。应用案例(1)应用层:通过调用hal层 mds_stores不能关闭 nicekwell macmacmds_storesalfred 有次发现mds_stores占用了很高的cpu,网上有人建议把它关掉:sudomdutil-a-ioff关掉之后发现alfred不能找到新安装的应用了,所以最好还是不要关掉。sudomdutil-a-ion macOS Catalina 10.15 - 新增功能及其他信息记录 伊织code Apple开发+10.15macOSCatalinaSidecar 文章目录推荐阅读参考一、基本信息WWDC2019壁纸二、beta版本安装macOS10.15Xcode11三、新功能添加屏幕使用时间iPadOS应用可在Mac上运行APFS宗卷被拆分为只读的系统宗卷(System)和用户数据宗卷(Data)增加Findmy查找添加由Siri控制的「捷径」和「屏幕时间」AppleWatch可解锁MacSidecar:将iPad作为副显示屏四、其他变更终端shell建 猎板 PCB:HDI 技术精要解读 lboyj 人工智能 HDI技术凭借增加盲埋孔的方式,达成了高密度布局,在高端服务器、智能手机、多功能POS机以及安防摄像机等诸多领域均有广泛应用。尤其在通讯和计算机行业中,对HDI线路板有着较高的需求,这在一定程度上有力地推动了科技的持续进步,使得HDI板在国内市场展现出十分乐观的发展前景。然而,HDI技术作为一种特殊工艺,也面临诸多挑战。一方面,其成本相对较高;另一方面,对制造商的生产能力有着严格要求。倘若缺乏先进 Spring Bean 生命周期详解 黑风风 java多线程springjava数据库 SpringBean生命周期详解在Spring框架中,Bean的生命周期由Spring容器全权管理。了解和掌握Bean的生命周期对于使用Spring开发稳定且高效的应用程序至关重要。本文将详细介绍SpringBean生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。1.实例化(Instantiation)实例化阶段包括以下关键步骤:BeanNameAw 国鑫DeepSeek 671B本地部署方案:以高精度、高性价比重塑AI推理新标杆 Gooxi国鑫 人工智能服务器 随着DeepSeek大模型应用火爆全球,官方服务器总是被挤爆。而且基于企业对数据安全、网络、算力的更高需求,模型本地化部署的需求日益增长,如何在有限预算内实现高效、精准的AI推理能力,成为众多企业的核心诉求。国鑫作为深耕AI领域的技术先锋,推出基于4台48GRTX4090或8台24GRTX4090服务器的2套DeepSeek“满血”版本地部署方案,以FP16高精度、高性价比、强扩展性三大优势,为企 Linux:从入门到精通的全面指南 dbsnc1111 linux运维服务器 一、引言Linux作为一种开源操作系统,犹如一座技术宝库,在当今的科技领域中占据着至关重要的地位。它以其卓越的稳定性、高度的安全性和无与伦比的灵活性,在服务器、嵌入式系统、个人计算机、超级计算机等众多领域广泛应用。无论是渴望提升技术水平的个人,还是寻求拓展职业道路的专业人士,学习Linux都无疑是开启新机遇之门的钥匙。以下是关于Linux的详细知识以及学习Linux的经验总结,希望能为正在学习或准 Spring Bean 生命周期的执行流程 涛粒子 spring数据库java 1.Bean定义阶段在Spring应用启动时,会读取配置文件(如XML配置、Java注解配置等)或者扫描带有特定注解(如@Component、@Service、@Repository等)的类,将这些Bean的定义信息加载到Spring的BeanFactory或ApplicationContext中。这些定义信息包括Bean的类名、作用域、依赖关系等。2.Bean实例化阶段调用构造函数:Spring 浅谈vue常用的状态管理库vuex、pinia 超绝前端乱学小白 vuefluttervue.jsvuejavascript Vuex和Pinia都是Vue.js应用程序中的状态管理库,虽然两种状态管理库的vue2,vue3都兼容,但是更推荐vue2(vuex),vue3(pinia)VuexVuex是Vue.js官方提供的状态管理库,它借鉴了Flux和Redux的设计思想,将应用的状态(state)集中管理于单个全局状态树中。核心概念State:存储应用程序的状态Getters:允许在Vuexstore中定义计算属性, 深入了解常见MCU架构:ARM、AVR与其他嵌入式系统 Crazy learner 模型部署架构mcu 目录**一、什么是MCU(微控制器单元)?****二、ARM架构微控制器****1.ARM架构简介****2.ARM架构特点****3.ARM架构应用领域****4.ARM架构的代表性MCU****三、AVR架构微控制器****1.AVR架构简介****2.AVR架构特点****3.AVR架构应用领域****4.AVR架构的代表性MCU****四、ARM与AVR架构对比****选择建议:****结 pycharm画图程序如何一步一步的调试 leaf_leaves_leaf pycharmidepython 1.设置合适的Matplotlib后端在PyCharm中,有时需要手动指定Matplotlib后端。你可以尝试在脚本的最开始加入以下代码,强制使用TkAgg后端,这样可以保证图形更新的实时性:importmatplotlibmatplotlib.use('TkAgg')#指定TkAgg后端importmatplotlib.pyplotaspltimportnumpyasnp#启用交互模式plt.i C语言中的回调函数 以及应用 C r a z y c语言c++javapython数据结构 定义回调函数就是一个通过函数指针调用的函数。如果你把函数的指针也就是地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就可以说这是回调函数。注意回调函数不是有该函数的实现方直接调用,而是再特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应看不懂没关系先继续看↓实例应用:我们先用常规思路写一个能简单实现加减乘除的计算器#includevoidmenu(){pr Spring Bean 生命周期的执行流程 涛粒子 springjava后端 1.Bean定义阶段解析配置元数据:Spring容器会读取配置信息,这些配置信息可以是XML文件、Java注解或者Java配置类。容器根据这些配置信息解析出Bean的定义,包括Bean的类名、作用域、依赖关系等。注册Bean定义:解析完成后,Spring会将Bean定义信息注册到BeanDefinitionRegistry中,BeanDefinitionRegistry是一个存储Bean定义的注册 PHP 网络编程介绍 来恩1003 PHP从入门到精通php网络开发语言 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,网络编程是开发各类应用必不可少的技能。PHP作为一门广泛应用于Web开发的编程语言,同样具备强大的网络编程能力。接下来,我们将深入探讨PHP中网络连接的建立、Socket编程、HTTP请求与响应等网络相关的操作。一、网络连接的建立在PHP中建立网络连接,主要是通过使用内置的函数来实现与远程服务器的通信。最常见的是使用fsockopen函数 PHP 安全与加密:守护 Web 应用的基石 来恩1003 PHP从入门到精通php安全前端 PHP学习资料PHP学习资料PHP学习资料在当今数字化时代,Web应用无处不在,而PHP作为一种广泛使用的服务器端脚本语言,承载着无数网站和应用的核心逻辑。然而,随着网络攻击手段日益复杂,PHP应用面临着诸多安全威胁,如SQL注入、XSS攻击等,同时,数据的加密保护也至关重要。本文将深入探讨PHP中的安全问题及加密算法的应用,帮助开发者构建更安全可靠的Web应用。一、PHP安全之殇——SQL注入攻 使用Druid连接池优化Spring Boot应用中的数据库连接 和烨 其它springboot数据库后端 使用Druid连接池优化SpringBoot应用中的数据库连接使用Druid连接池优化SpringBoot应用中的数据库连接1.什么是Druid连接池?2.在SpringBoot中配置Druid连接池2.1添加依赖2.2配置Druid连接池2.3配置参数详解3.启用Druid监控4.总结使用Druid连接池优化SpringBoot应用中的数据库连接在现代的Java应用中,数据库连接管理是一个非常重 jvm虚拟机详解(一)-----jvm概述 Mir Su JVM由浅至深jvmjava 写在前面本篇文章是再下人生中的第一次发布关于技术相关的文章。从事开发工作这么多年来,也算是对自己过往的工作的一个总结,对人生的一次重装再出发。从jvm谈起,然后是关于mysql、redis、消息中间件、微服务等最后在归纳一些常见的java面试方面的高频问题。这是开始我的一个写博计划,希望感兴趣的朋友加个关注一起探讨,有什么不做的地方也请欢迎指教。为什么要先说jvm呢?因为jvm是java程序蜕变的 vue中使用ueditor上传到服务器_vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑]... 小西超人 写在最前面的话:鉴于近期很多的博友讨论,说我按照文章的一步一步来,弄好之后,怎么会提示后端配置项http错误,文件上传会提示上传错误。这里提别申明一点,ueditor在前端配置好后,需要与后端部分配合进行,后端部分的项目代码git地址:https://github.com/coderliguoqing/UeditorSpringboot,然后将配置ueditor.config.js里的server java新技术 计算机毕业设计系统 转载:http://lj6684.iteye.com/blog/895010最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收1.JNAJNI的替代品,调用方式比JNI更直接,不再需要JNI那层中间接口,几乎达到Java直接调用动态库2.SmallSQL基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,不支持网络但目前好像不太活跃,最新版本是0. 国产编辑器EverEdit - 独门暗器:自动监视剪贴板内容 编辑器爱好者 妙用编辑器编辑器EverEditEmEditorNotepad 1监视剪贴板1.1应用场景 如果需要对剪贴板的所有历史进行记录,并进行分析和回顾,则可以使用监视剪贴板功能,不仅在EverEdit中的复制会记录,在其他应用的复制也会记录。1.2使用方法 新建一个空文档(重要:防止扰乱正常文件),单击主菜单文档->监视剪贴板即可。该功能打开后,当前系统所有的复制内容,都会追加到用户指定的文档中。说明:监视剪贴板只会监控文本内容,图片、文档等非文本信息,不会追加 基于Linux平台的多实例RTSP|RTMP直播播放器深度解析与技术实现 音视频牛哥 RTSP播放器RTMP播放器大牛直播SDK音视频实时音视频视频编解码linuxrtsp播放器linuxrtmp播放器linux国产rtmp播放器linux国产rtsp播放器 一、引言在Linux平台上实现一个高性能、高并发的多实例播放器,是许多流媒体应用的核心需求。本文将结合大牛直播SDK的Linux平台RTSP/RTMP播放器功能,深入解析其实现原理、关键技术点以及优化策略。通过对代码的详细分析和实际应用的结合,帮助开发者更好地理解和应用该技术。二、项目概述本文基于以下代码实现了一个多实例播放器:multi_player_demo.cpp:主程序,负责初始化SDK、 Vision Transformer(ViT):用 Transformer 颠覆图像识别 金外飞176 论文精读transformer深度学习人工智能 VisionTransformer(ViT):用Transformer颠覆图像识别在计算机视觉领域,卷积神经网络(CNN)长期以来一直是图像识别任务的主流架构。然而,近年来,自然语言处理(NLP)领域中大放异彩的Transformer架构也开始在图像识别中崭露头角。今天,我们将深入探讨一种创新的架构——VisionTransformer(ViT),它将Transformer的强大能力直接应用于图像 路由导航守卫 治金的blog Vue3学习前端javascript开发语言 路由导航守卫(NavigationGuards)是VueRouter提供的功能,用于控制用户在应用中的导航行为。简单来说,它们允许你在用户访问不同路由时执行一些代码,比如检查用户是否登录、加载数据或阻止导航等。比喻:可以将其想象成机场的安检。安检元在你登机前会检查你的证件和行李,确保一切符合要求,然后才允许你进入登机口。路由导航守卫的主要类型1.全局守卫:(全局守卫就像博物馆的总管理员,负责在你进 Java 与设计模式(15):模板方法模式 暗星涌动 设计模式java设计模式模板方法模式springboot 一、定义模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架(也就是大致的步骤和流程),而将一些具体步骤的实现延迟到子类中。这样,子类可以不改变算法的结构即可重新定义算法的某些特定步骤。二、Java示例举个简单的例子:假设我们要泡一杯茶和一杯咖啡,这两者的制作过程有一些共同的步骤,比如烧水、倒水、搅拌等,但也有不同的地方,比如茶需要放茶叶,而咖啡需要放咖啡粉。泡茶的过程:烧水、放茶叶、倒 基于若依和flowable6.7.2的ruoyi-nbcio流程管理系统正式发布 宁波阿成 ruoyi-nbcio若依flowableflowable若依ruoyi-nbcioruoyijavavue 更多ruoyi-nbcio功能请看演示系统gitee源代码地址前后端代码:https://gitee.com/nbacheng/ruoyi-nbcio演示地址:RuoYi-Nbcio后台管理系统项目概要本项目基于RuoYi-Flowable-Plus进行二次开发,从nbcio-boot(https://gitee.com/nbacheng/nbcio-boot)项目</ eclipse maven IXHONG eclipse eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 可以设一个环境变量M2_HOME指 timer cancel方法的一个小实例 alleni123 多线程timer package com.lj.timer; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class MyTimer extends TimerTask { private int a; private Timer timer; pub MySQL数据库在Linux下的安装 ducklsl mysql 1.建好一个专门放置MySQL的目录 /mysql/db数据库目录 /mysql/data数据库数据文件目录 2.配置用户,添加专门的MySQL管理用户 >groupadd mysql ----添加用户组 >useradd -g mysql mysql ----在mysql用户组中添加一个mysql用户 3.配置,生成并安装MySQL >cmake -D spring------>>cvc-elt.1: Cannot find the declaration of element Array_06 springbean 将-------- <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3 maven发布第三方jar的一些问题 cugfy maven maven中发布 第三方jar到nexus仓库使用的是 deploy:deploy-file命令 有许多参数,具体可查看 http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html 以下是一个例子: mvn deploy:deploy-file -DgroupId=xpp3 MYSQL下载及安装 357029540 mysql 好久没有去安装过MYSQL,今天自己在安装完MYSQL过后用navicat for mysql去厕测试链接的时候出现了10061的问题,因为的的MYSQL是最新版本为5.6.24,所以下载的文件夹里没有my.ini文件,所以在网上找了很多方法还是没有找到怎么解决问题,最后看到了一篇百度经验里有这个的介绍,按照其步骤也完成了安装,在这里给大家分享下这个链接的地址 ios TableView cell的布局 张亚雄 tableview cell.imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:[indexPath row]]]; CGSize itemSize = CGSizeMake(60, 50); &nbs Java编码转义 adminjun java编码转义 import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */ public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final Strin Tomcat 配置和spring aijuans spring 简介 Tomcat启动时,先找系统变量CATALINA_BASE,如果没有,则找CATALINA_HOME。然后找这个变量所指的目录下的conf文件夹,从中读取配置文件。最重要的配置文件:server.xml 。要配置tomcat,基本上了解server.xml,context.xml和web.xml。 Server.xml -- tomcat主 Java打印当前目录下的所有子目录和文件 ayaoxinchao 递归File 其实这个没啥技术含量,大湿们不要操笑哦,只是做一个简单的记录,简单用了一下递归算法。 import java.io.File; /** * @author Perlin * @date 2014-6-30 */ public class PrintDirectory { public static void printDirectory(File f linux安装mysql出现libs报冲突解决 BigBird2012 linux linux安装mysql出现libs报冲突解决 安装mysql出现 file /usr/share/mysql/ukrainian/errmsg.sys from install of MySQL-server-5.5.33-1.linux2.6.i386 conflicts with file from package mysql-libs-5.1.61-4.el6.i686 jedis连接池使用实例 bijian1013 redisjedis连接池jedis 实例代码: package com.bijian.study; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoo 关于朋友 bingyingao 朋友兴趣爱好维持 成为朋友的必要条件: 志相同,道不合,可以成为朋友。譬如马云、周星驰一个是商人,一个是影星,可谓道不同,但都很有梦想,都要在各自领域里做到最好,当他们遇到一起,互相欣赏,可以畅谈两个小时。 志不同,道相合,也可以成为朋友。譬如有时候看到两个一个成绩很好每次考试争做第一,一个成绩很差的同学是好朋友。他们志向不相同,但他 【Spark七十九】Spark RDD API一 bit1129 spark aggregate package spark.examples.rddapi import org.apache.spark.{SparkConf, SparkContext} //测试RDD的aggregate方法 object AggregateTest { def main(args: Array[String]) { val conf = new Spar ktap 0.1 released bookjovi kerneltracing Dear, I'm pleased to announce that ktap release v0.1, this is the first official release of ktap project, it is expected that this release is not fully functional or very stable and we welcome bu 能保存Properties文件注释的Properties工具类 BrokenDreams properties 今天遇到一个小需求:由于java.util.Properties读取属性文件时会忽略注释,当写回去的时候,注释都没了。恰好一个项目中的配置文件会在部署后被某个Java程序修改一下,但修改了之后注释全没了,可能会给以后的参数调整带来困难。所以要解决这个问题。 &nb 读《研磨设计模式》-代码笔记-外观模式-Facade bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ /* * 百度百科的定义: * Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面, * 隐藏子系统的复杂性,使子系统更加容易使用。他是为子系统中的一组接口所提供的一个一致的界面 * * 可简单地 After Effects教程收集 cherishLC After Effects 1、中文入门 http://study.163.com/course/courseMain.htm?courseId=730009 2、videocopilot英文入门教程(中文字幕) http://www.youku.com/playlist_show/id_17893193.html 英文原址: http://www.videocopilot.net/basic/ 素 Linux Apache 安装过程 crabdave apache Linux Apache 安装过程 下载新版本: apr-1.4.2.tar.gz(下载网站:http://apr.apache.org/download.cgi) apr-util-1.3.9.tar.gz(下载网站:http://apr.apache.org/download.cgi) httpd-2.2.15.tar.gz(下载网站:http://httpd.apac Shell学习 之 变量赋值和引用 daizj shell变量引用赋值 本文转自:http://www.cnblogs.com/papam/articles/1548679.html Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z) 中间不能有空格,可以使用下划线(_) 不能使用标点符号 不能使用bash里的关键字(可用help命令查看保留关键字) 需要给变量赋值时,可以这么写: Java SE 第一讲(Java SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行) dcj3sjt126com javajdk Java SE 第一讲: Java SE:Java Standard Edition Java ME: Java Mobile Edition Java EE:Java Enterprise Edition Java是由Sun公司推出的(今年初被Oracle公司收购)。 收购价格:74亿美金 J2SE、J2ME、J2EE JDK:Java Development YII给用户登录加上验证码 dcj3sjt126com yii 1、在SiteController中添加如下代码: /** * Declares class-based actions. */ public function actions() { return array( // captcha action renders the CAPTCHA image displ Lucene使用说明 dyy_gusi Lucenesearch分词器 Lucene使用说明 1、lucene简介 1.1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像baidu或者googleDesktop那种拿来就能用,它只是提供了一种工具让你能实现这些产品和功能。 1.2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际 学习编程并不难,做到以下几点即可! gcq511120594 数据结构编程算法 不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 1、确定目标 学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到 Java面试十问之三:Java与C++内存回收机制的差别 HNUlanwei javaC++finalize()堆栈内存回收 大家知道, Java 除了那 8 种基本类型以外,其他都是对象类型(又称为引用类型)的数据。 JVM 会把程序创建的对象存放在堆空间中,那什么又是堆空间呢?其实,堆( Heap)是一个运行时的数据存储区,从它可以分配大小各异的空间。一般,运行时的数据存储区有堆( Heap)和堆栈( Stack),所以要先看它们里面可以分配哪些类型的对象实体,然后才知道如何均衡使用这两种存储区。一般来说,栈中存放的 第二章 Nginx+Lua开发入门 jinnianshilongnian nginxlua Nginx入门 本文目的是学习Nginx+Lua开发,对于Nginx基本知识可以参考如下文章: nginx启动、关闭、重启 http://www.cnblogs.com/derekchen/archive/2011/02/17/1957209.html agentzh 的 Nginx 教程 http://openresty.org/download/agentzh-nginx-tutor MongoDB windows安装 基本命令 liyonghui160com windows安装 安装目录: D:\MongoDB\ 新建目录 D:\MongoDB\data\db 4.启动进城: cd D:\MongoDB\bin mongod -dbpath D:\MongoDB\data\db &n Linux下通过源码编译安装程序 pda158 linux 一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通常是我们在linux下用man命令查看的命令的文档 二、linux下程序的存放目录 linux程序的存放目录大致有三个地方: /etc, /b WEB开发编程的职业生涯4个阶段 shw3588 编程Web工作生活 觉得自己什么都会 2007年从学校毕业,凭借自己原创的ASP毕业设计,以为自己很厉害似的,信心满满去东莞找工作,找面试成功率确实很高,只是工资不高,但依旧无法磨灭那过分的自信,那时候什么考勤系统、什么OA系统、什么ERP,什么都觉得有信心,这样的生涯大概持续了约一年。 根本不是自己想的那样 2008年开始接触很多工作相关的东西,发现太多东西自己根本不会,都需要去学,不管是asp还是js, 遭遇jsonp同域下变作post请求的坑 vb2005xu jsonp同域post 今天迁移一个站点时遇到一个坑爹问题,同一个jsonp接口在跨域时都能调用成功,但是在同域下调用虽然成功,但是数据却有问题. 此处贴出我的后端代码片段 $mi_id = htmlspecialchars(trim($_GET['mi_id '])); $mi_cv = htmlspecialchars(trim($_GET['mi_cv '])); 贴出我前端代码片段: $.aj 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
package com.messi.netty_core_02.netty11; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.logging.LoggingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Description TODO * @Author etcEriksen * @Date 2023/12/20 9:43 * @Version 1.0 */ public class MyNettyServer { private static final Logger log = LoggerFactory.getLogger(MyNettyServer.class); public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(new NioEventLoopGroup(1),new NioEventLoopGroup(8)); DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(); serverBootstrap.childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * maxFrameLength:数据包最大长度为1024字节 * lengthFieldOffset:数据长度字段前面有多少字节的偏移? * lengthAdjustment:数据长度字段与真实数据体之间有多少距离? * initialBytesToStrip:最终服务端输出的数据去除前面多少字节的长度? * 具体见:Netty应用04-Netty这一笔记 */ pipeline.addLast(new LoggingHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder (1024,11,4,0,0)); pipeline.addLast(new MyByte2MessageDecoder()); pipeline.addLast(defaultEventLoopGroup,new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg ; log.info("服务端接收到客户端的数据为:{}",message) ; } }); } }); serverBootstrap.bind(8000); System.out.println("MyNettyServer.main"); } }