范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

通过实际的案例详解Netty中LengthFieldBasedFrameDecoder的使用

  概述
  本文通过一个具体的案例来详细介绍 LengthFieldBasedFrameDecoder 的使用,在案例中通过对数据的封包和解包实现对数据的加密,压缩,解压,解密等操作。 关键点服务器端在启动的时候开放一个端口:19080 客户端在启动的时候通过 ip 和 端口连上服务器端 客户端和服务器端都通过 Channel 对象向彼此发送数据 服务器和客户端都通过继承 ChannelInboundHandlerAdapter 类实现对 消息实体 的读取和回写等操作 服务器和客户端都通过 LengthFieldBasedFrameDecoder 和 CommonDataEncoder 实现对 消息实体 的解码和转码操作 服务器和客户端启动的时候都会阻塞当前线程,因此需要在一个单独的线程中进行启动 服务器和客户端都在 发送数据 前 进行加密和压缩 服务器和客户端都在 接收数据 后 进行解压和解密 服务器和客户端需要确保发送的数据的字节长度不能超过 LengthFieldBasedFrameDecoder 设置的最大帧长度 使用案例介绍本例是一个 spring boot web 项目,项目占用了 8080 端口 服务器端在启动的时候开放 19080 端口(注意不要和 web 端口冲突了) 客户端在启动的时候连上服务器端 通过 web api 向客户端发送数据,客户端再通过 Channel 对象向服务器端发送数据 服务器接收到客户端数据后也通过 Channel 对象向客户端发送数据 客户端和服务器端通过 CommonData 对象进行消息的封装和传输,并通过 LengthFieldBasedFrameDecoder 实现对数据的解码。 消息实体 CommonDataCommonData 的定义如下 @Data @NoArgsConstructor @AllArgsConstructor @Builder public class CommonData {     // byte 表示的数据范围是 -128到127 之间,因此可以直接通过将 -128到127的数字通过 (byte)[-128 - 127] 方式强制转换     // 类型  系统编号 1 表示A系统,2 表示B系统     private byte type;     // 信息标志  1 表示心跳包  2 表示超时包 3 业务信息包     private byte flag;     // 主题信息的字节长度,     private int length;     // 主题信息     private String body; }     LengthFieldBasedFrameDecoder 构造方法介绍public LengthFieldBasedFrameDecoder(             int maxFrameLength,             int lengthFieldOffset, int lengthFieldLength,             int lengthAdjustment, int initialBytesToStrip)
  那么这几个重要的参数如下: maxFrameLength:最大帧长度。也就是可以接收的数据的最大长度。如果超过,此次数据会被丢弃。 lengthFieldOffset:长度域偏移。就是说数据开始的几个字节可能不是表示数据长度,需要后移几个字节才是长度域。 lengthFieldLength:长度域字节数。用几个字节来表示数据长度。 lengthAdjustment:数据长度修正。因为长度域指定的长度可以使 header+body 的整个长度,也可以只是body的长度。如果表示header+body的整个长度,那么我们需要修正数据长度。 initialBytesToStrip:跳过的字节数。如果你需要接收 header+body 的所有数据,此值就是0,如果你只想接收body数据,那么需要跳过header所占用的字节数。 LengthFieldBasedFrameDecoder 的构造参数
  LengthFieldBasedFrameDecoder 是 Netty 中解决拆包粘包问题的一个重要的类,主要结构就是 header+body 结构。只需要传入正确的参数就可以发送和接收正确的数据。 根据 CommonData 的定义,可以知道对应 LengthFieldBasedFrameDecoder 的构造参数如下 private static final int MAX_FRAME_LENGTH = 1024 * 1024; private static final int LENGTH_FIELD_OFFSET = 2; // 第一个字节是 type, 第二个字节是 flag, 因此偏移是 2 private static final int LENGTH_FIELD_LENGTH = 4; // 存储数据字节长度的是 int 类型,含有四个字节。 private static final int LENGTH_ADJUSTMENT = 0; private static final int INITIAL_BYTES_TO_STRIP = 0;  ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(MAX_FRAME_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP, true)); 对消息实体 CommonData 进行加密,压缩,解压,解密等操作将 对象转成 加密,压缩 后的字节数组 将 字节数组 解压,解密 后转成 java 对象 /**  * 将 对象转成 加密,压缩后的字节数组  *  * @return bytes 数组  */ public static ByteBuf toBytes(CommonData commonData) {     // 1 对 body 进行加密     byte[] bodyBytes = commonData.getBody().getBytes(StandardCharsets.UTF_8);     byte[] bodyEncryptBytes = AESUtils.encrypt(bodyBytes, "123456");     // 2 对 body 进行压缩     byte[] bodyEncryptGzipBytes = GZIPUtils.compress(bodyEncryptBytes);      ByteBuf byteBuf = Unpooled.directBuffer(1+1+4+bodyEncryptGzipBytes.length);     byteBuf.writeByte(commonData.getType());     byteBuf.writeByte(commonData.getFlag());     byteBuf.writeInt(bodyEncryptGzipBytes.length);     byteBuf.writeBytes(bodyEncryptGzipBytes);     int size = byteBuf.capacity();     return byteBuf; }  /**  * 将字节数组 解压,解密后转成 java 对象  *  * @param byteBuf ByteBuf 对象  * @return CommonData  */ public static CommonData fromBytes(ByteBuf byteBuf) {     byte type = byteBuf.readByte();     byte flag = byteBuf.readByte();     int length = byteBuf.readInt();     byte[] bodyBytes = new byte[length];     byteBuf.readBytes(bodyBytes);     // 1 对 body 解压     byte[] bodyUnCompressBytes = GZIPUtils.uncompress(bodyBytes);     // 2 对 body 解密     byte[] bodyDecryptBytes = AESUtils.decrypt(bodyUnCompressBytes, "123456");     return CommonData.builder().type(type).flag(flag).length(length).body(new String(bodyDecryptBytes, StandardCharsets.UTF_8)).build(); } 通用消息转码类 CommonDataEncoder服务器端和客户端在 业务处理类 都是直接将 消息体 直接写入的 channel 中的 在 CommonDataEncoder 类中才会对 消息体 进行 加密和压缩处理 服务器端和客户端分别在 业务处理类 中对 消息体 进行解压和解密处理 package com.ckjava.test.netty.encoder;  import com.ckjava.test.netty.vo.CommonData; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder;  /**  * @author ckjava  * @date 2022/4/23 21:26  */ public class CommonDataEncoder extends MessageToByteEncoder {      /**      * 将数据转成字节      * @param ctx      * @param msg      * @param out      * @throws Exception      */     @Override     protected void encode(ChannelHandlerContext ctx, CommonData msg, ByteBuf out) throws Exception {         if (null == msg) {             throw new Exception("msg is null");         }         out.writeBytes(CommonData.toBytes(msg));     } } 服务器端启动类通过 init 方法启动 Netty Server 通过 childHandler 绑定 CommonDataEncoder,LengthFieldBasedFrameDecoder,CommonServerDataHandler package com.ckjava.test.server;  import com.ckjava.test.netty.encoder.CommonDataEncoder; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;  import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.net.InetSocketAddress; import java.util.concurrent.ForkJoinPool;  @Slf4j @Component public class CommonNettyServer {      private static final int MAX_FRAME_LENGTH = 1024 * 1024;     private static final int LENGTH_FIELD_OFFSET = 2; // 第一个字节是 type, 第二个字节是 flag, 因此偏移是 2     private static final int LENGTH_FIELD_LENGTH = 4; // 存储数据字节长度的是 int 类型,含有四个字节。     private static final int LENGTH_ADJUSTMENT = 0;     private static final int INITIAL_BYTES_TO_STRIP = 0;      private static final EventLoopGroup bossGroup = new NioEventLoopGroup(1);     private static final EventLoopGroup workerGroup = new NioEventLoopGroup();      public void startServer(int port) {         try {             ServerBootstrap sbs = new ServerBootstrap().group(bossGroup, workerGroup)                     .channel(NioServerSocketChannel.class)                     .localAddress(new InetSocketAddress(port))                     .childHandler(new ChannelInitializer() {                         @Override                         protected void initChannel(final SocketChannel ch) {                             ch.pipeline().addLast(new CommonDataEncoder());                             ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(MAX_FRAME_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP, true));                             ch.pipeline().addLast(new CommonServerDataHandler());                         }                     })                     .option(ChannelOption.SO_BACKLOG, 128)                     .childOption(ChannelOption.SO_KEEPALIVE, true);             // 绑定端口,开始接收进来的连接             sbs.bind(port).addListener(future -> {                 log.info(String.format("服务器启动成功,并监听端口:%s ", port));             });          } catch (Exception e) {             log.error("启动 netty 服务器端出现异常", e);         }     }      // 服务器端启动,并绑定 19080 端口     @PostConstruct     public void init() {         ForkJoinPool.commonPool().submit(() -> startServer(19080));     }      @PreDestroy     public void destroy() {         bossGroup.shutdownGracefully();         workerGroup.shutdownGracefully();     } } 服务器端业务处理类继承 SimpleChannelInboundHandler 类,用于接收客户端发送的消息体,并向客户端返回数据。 通过 CommonData.fromBytes(byteBuf) 将接收的数据进行解压,解密 向客户端返回数据由 CommonDataEncoder 进行加密和压缩处理 通过 handleMap 封装具体的业务逻辑 package com.ckjava.test.server;  import com.ckjava.test.netty.vo.CommonData; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import lombok.extern.slf4j.Slf4j;  import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.function.Function;  /**  * @author ckjava  * @date 2022/4/23 21:31  */ @Slf4j public class CommonServerDataHandler extends SimpleChannelInboundHandler {      @Override     protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) {         CommonData commonData = CommonData.fromBytes(byteBuf);         log.info(String.format("服务器端从客户端读取的数据:%s", commonData.toString()));         String key = String.valueOf(commonData.getType()).concat(String.valueOf(commonData.getFlag()));         if (Objects.nonNull(handleMap.get(key))) {             ctx.channel().writeAndFlush(handleMap.get(key).apply(commonData));         } else {             CommonData r = handleMap.get(null).apply(commonData);             ctx.channel().writeAndFlush(r);         }     }      // 捕获到异常的处理     @Override     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {         cause.printStackTrace();         ctx.close();     }      private static Map> handleMap = new HashMap>() {{         // 业务系统 1 的心跳         put("11", commonData -> {             String data = "心跳 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的 超时处理逻辑         put("12", commonData -> {             String data = "超时处理 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的业务处理逻辑         put("13", commonData -> {             String data = "业务处理 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的心跳         put("21", commonData -> {             String data = "心跳 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的 超时处理逻辑         put("22", commonData -> {             String data = "超时处理 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的业务处理逻辑         put("23", commonData -> {             String data = "业务处理 ok";             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });          // 业务系统 1 的业务处理逻辑         put(null, commonData -> {             String data = String.format("服务:%s 不支持,result:%s", commonData.getType(), "no available");             commonData.setLength(data.getBytes(StandardCharsets.UTF_8).length);             commonData.setBody(data);             return commonData;         });     }};  }  客户端启动类通过 init 方法启动客户端 通过 childHandler 绑定 CommonDataEncoder,LengthFieldBasedFrameDecoder,CommonServerDataHandler package com.ckjava.test.client;  import com.ckjava.test.netty.encoder.CommonDataEncoder; import com.ckjava.test.netty.vo.CommonData; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;  import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.nio.charset.StandardCharsets; import java.util.concurrent.ForkJoinPool;  @Slf4j @Component public class CommonNettyClient {      private static final int MAX_FRAME_LENGTH = 1024 * 1024;     private static final int LENGTH_FIELD_OFFSET = 2; // 第一个字节是 type, 第二个字节是 flag, 因此偏移是 2     private static final int LENGTH_FIELD_LENGTH = 4; // 存储数据字节长度的是 int 类型,含有四个字节。     private static final int LENGTH_ADJUSTMENT = 0;     private static final int INITIAL_BYTES_TO_STRIP = 0;      private final EventLoopGroup group = new NioEventLoopGroup();     private ChannelFuture mChannelFuture = null;     private final ThreadLocal mChannel = new ThreadLocal<>();      public void startClient(String host, int port) {         // Configure the client.         try {             Bootstrap b = new Bootstrap();             b.group(group)                     .channel(NioSocketChannel.class)                     .option(ChannelOption.TCP_NODELAY, true)                     .handler(new ChannelInitializer() {                         @Override                         public void initChannel(SocketChannel ch) {                             ch.pipeline().addLast(new CommonDataEncoder());                             ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(MAX_FRAME_LENGTH, LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP, true));                             ch.pipeline().addLast(new CommonClientDataHandler());                         }                     });              mChannelFuture = b.connect(host, port).addListener(future -> {                 log.info(String.format("客户端启动成功,连接端口:%s ", port));             });         } catch (Exception e) {             log.error("启动 netty 客户端出现异常", e);         }     }      /**      * 客户端通过 Channel 对象向服务器端发送数据      * @param data 文本数据      */     public void send(CommonData data) {         try {             if (mChannel.get() == null) {                 mChannel.set(mChannelFuture.channel());             }             data.setLength(data.getBody().getBytes(StandardCharsets.UTF_8).length);             mChannel.get().writeAndFlush(data);         } catch (Exception e) {             log.error(this.getClass().getName().concat(".send has error"), e);         } finally {             mChannel.get().closeFuture();         }     }      // 客户端启动,并连上服务器端     @PostConstruct     public void init() {         ForkJoinPool.commonPool().submit(() -> startClient("127.0.0.1", 19080));     }      @PreDestroy     public void destroy() {         group.shutdownGracefully();     }  } 客户端业务处理类通过 channelRead0 方法读取服务器端发送过来的数据 通过 channelActive 方法在启动的时候主动向服务器端发送消息 在接收消息的时候需要进行解压,解密操作 package com.ckjava.test.client;  import com.ckjava.test.netty.vo.CommonData; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import lombok.extern.slf4j.Slf4j;  import java.nio.charset.StandardCharsets;  /**  * @author ckjava  * @date 2022/4/23 21:33  */ @Slf4j public class CommonClientDataHandler extends SimpleChannelInboundHandler {      @Override     public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) {         log.info(String.format("客户端读取从服务器端发送过来的数据:%s", CommonData.fromBytes(byteBuf).toString()));     }      @Override     public void channelActive(ChannelHandlerContext ctx) {         String data = "Hello,Netty";         CommonData commonData = CommonData.builder()                 .type((byte) 1)                 .flag((byte) 1)                 .length(data.getBytes(StandardCharsets.UTF_8).length)                 .body(data)                 .build();         ctx.writeAndFlush(commonData);     }      // 捕获到异常的处理     @Override     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {         cause.printStackTrace();         ctx.close();     } }  通过 api 向 Netty client 发送数据
  这里为了测试方便,通过 api 向 Netty client 发送数据,Netty client 再将数据发送给 服务器端。 package com.ckjava.test.web;  import com.ckjava.test.client.CommonNettyClient; import com.ckjava.test.netty.vo.CommonData; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import javax.annotation.Resource;  /**  * @author ckjava  * @date 2022/4/18 23:50  */ @Api @RequestMapping(produces = "application/json;charset=utf-8") @RestController public class CommonDataCtrl {      @Resource     private CommonNettyClient mHelloWorldClient;      @PostMapping("/nettyClient")     public void nettyClient(@RequestBody CommonData data) {         mHelloWorldClient.send(data);     } }  测试通过 api 发送数据如下 curl -X POST "http://localhost:8080/nettyClient" -H "accept: application/json;charset=utf-8" -H "Content-Type: application/json" -d "{ "body": "ckjava", "flag": 1, "length": 0, "type": 1}" 输出如下 16:48:09.471 [nioEventLoopGroup-3-1] INFO  c.c.test.server.CommonNettyServer - 服务器启动成功,并监听端口:19080  16:48:09.478 [nioEventLoopGroup-2-1] INFO  c.c.test.client.CommonNettyClient - 客户端启动成功,连接端口:19080  16:48:09.928 [nioEventLoopGroup-4-1] INFO  c.c.t.server.CommonServerDataHandler - 服务器端从客户端读取的数据:CommonData(type=1, flag=1, length=37, body=Hello,Netty) 16:48:09.929 [nioEventLoopGroup-2-1] INFO  c.c.t.client.CommonClientDataHandler - 客户端读取从服务器端发送过来的数据:CommonData(type=1, flag=1, length=37, body=心跳 ok) 16:48:13.449 [http-nio-8080-exec-1] INFO  o.a.tomcat.util.http.parser.Cookie - A cookie header was received [1650709813,1651396672,1651397189] that contained an invalid cookie. That cookie will be ignored.Note: further occurrences of this error will be logged at DEBUG level. 16:48:13.456 [http-nio-8080-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet "dispatcherServlet" 16:48:13.456 [http-nio-8080-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet "dispatcherServlet" 16:48:13.465 [http-nio-8080-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 9 ms 16:48:13.534 [nioEventLoopGroup-4-1] INFO  c.c.t.server.CommonServerDataHandler - 服务器端从客户端读取的数据:CommonData(type=1, flag=1, length=37, body=ckjava) 16:48:13.536 [nioEventLoopGroup-2-1] INFO  c.c.t.client.CommonClientDataHandler - 客户端读取从服务器端发送过来的数据:CommonData(type=1, flag=1, length=37, body=心跳 ok)

利用Python帮你偷懒自动拍摄开机人照片发送指定邮箱笔记本电脑的提供了便携性,同时也带来了一些问题,最常见的就是弄丢电脑,或者是笔记本电脑未设置开机密码被其他人随意开机。那么我们如何解决这个问题呢?通过python,我们可以在笔记本浙商证券给予国联股份买入评级20220117浙商证券股份有限公司于健,陈腾曦对国联股份进行研究并发布了研究报告国联股份更新点评数字经济载体,工业互联网龙头,本报告对国联股份给出买入评级,当前股价为117。89小K播早报国务院积极建设城际充电网和高速路快充设施微软作价687亿美元收购动视暴雪科创板日报(上海,王古锋)讯,今日科创板早报主要内容有工信部将持续加强光伏产业顶层设计,推动产业智能升级中国人民银行称2022年加大对实体经济科技创新绿色发展的支持力度紫光国微预计Nginx无法获取带下划线的请求头数据问题一前言1。1背景今天在开发中有这样一个请求前端需要在http请求中携带参数,后端获取参数进行解析并进行后续操作。1。2运行环境前后端分离前端Nuxtaxios后端Springboo百世集团收到纽交所退市警告微软687亿美元并购动视暴雪出品搜狐科技编辑黄小芳今天是1月19日,周三。昨夜今晨,科技圈有哪些大事发生,请关注今日科技早报。百世收到纽交所退市警告1月18日,百世集团发布公告称,公司收到纽约证券交易所于20颠覆者周鸿祎自传圆月书单颠覆者周鸿祎自传周鸿祎范海涛201722。6w字一本周鸿祎前半生传记,讲述从孩童到2011年360上市自己的创业过程。他的理想主义不达目的不罢休的执拗性格跃然纸上。虽是知名企业家却Python其实很简单第五章基本数据类型编程的目的就是为了处理信息,信息则是由各种不同类型的数据表示的,对数据的进一步处理也会使信息更加丰富和有效。5。1变量前面已经提到过变量这属语,下面再进一步解释一下。在程序运行时,第三届中国工业互联网大赛启动全国总决赛中新网北京1月19日电(记者刘育英)第三届中国工业互联网大赛19日正式启动全国总决赛,晋级全国总决赛的百强团队,将以团队线上比赛评委当场亮分的形式进行两天的激烈角逐,全国总决赛奖金支付宝集五福又开始了,如何快速集五福呢?虎年到啦,又到了支付宝集五福的时候,今天19号至31号开展为期十二天的集五福活动,刚开始活动,便微博上了热搜。爱国福,和谐福,友善福,富强福,敬业福。其中敬业福比较难获得,每年呢,facebook商城不是个新项目最近看到很多地方说facebook商城是个新项目,这个项目已经好几年了,下面我就给大家彻底地说一说这个项目,特别是小白,更应该看完。1。什么是facebook?他是一款聊天软件,老山东建成并开通5G基站超过10万个大众网海报新闻记者吴军林济南报道1月19日,山东省政府新闻办召开新闻发布会,介绍2021年全省经济社会运行情况。2021年,全省固定资产投资累计增长6,两年平均增长4。8,分别好于
画图狗一枚,想换一台流畅点的电脑,预算在7K左右,求推荐,真不晓得该怎么挑,期望能用个35年有咩有?关键两点第一点CPU最好是e3或者e5,主频3。4以上或者直接i511代高主频!第二点加原装Quadro专业绘图卡,4g以上的显卡,渲染杠杠的!第三点电源功率必须达标!下来应该不超性能小金刚!RedmiNote11T本月亮相续航非常强自RedmiK50系列亮相后,小米集团中国区总裁Redmi品牌总经理卢伟冰此前已经多次暗示RedmiNote系列新品即将带来,随后全新的RedmiNote11T系列正式得到官宣,该折叠屏新机华为P50Pocket发布,华为P50加速降价进行中,限时福利说起华为手机给我的印象,早先还停留在商务旗舰的水平。在我的认知里,华为的系统界面比较复古,设计硬朗,不太适合年轻的上手,然而近年来,华为手机开始有所突破。随着nova和P系列的成功小米11Ultra换成vivoX80,重度使用一周以后,心里憋了好多话要说大家平时会花多少钱买手机?相信3000元4000元会是大多数人的选择,这个价位的手机基本上普通人比较容易接受,使用体验跟旗舰机比较接近,非常具有性价比,各家手机厂商也是铆足了劲,在学生党2022适合学生党的性价比超高千元机现在很多手机都已经特别注重了性价比!今天就来给大家推荐千元机性价比超高的手机!第一款RealmeQ3s当前价格1299手机搭载了骁龙778处理器,更有144Hz的变帧电竞屏加上50联想PC不是第一?这里面恐怕有个天大的误会近来看到一则海外媒体报道,提到国内相关部门将在两年内将国外品牌电脑更换为国产电脑,涉及数量高达5000万台。消息真假不论,里面提到的一个观点苹果取代联想成为市场第一名,恐怕给外界造恭喜EDG夺冠!Flag今日兑现,花5w买的Python,java资料免费送恭喜EDG夺冠!Flag今日兑现,花5w买的Python,java资料免费送恭喜EDG夺冠!Flag今日兑现,花5w买的Python,java资料免费送恭喜EDG夺冠!Flag今日前行路上的探索2022数字化运营白皮书节选三前言放眼世界,我们面对的是百年未有之大变局。在当今的世界中,百年变局与疫情交织,全球经济受到大冲击,截至目前尚未从余波中脱身。物联网云计算人工智能大数据5G等技术的发展日新月异,彼世界电信日5。17又双叒来了!5月17日一年一度的世界电信日又双叒来了话不多说下面让我们携手密云区反诈形象大使著名演员谢苗共同加入全民反诈的队伍中吧!视频加载中电信诈骗有哪些类型呢?一冒充类诈骗此类诈骗主要是1新能源车补贴大调整车补变电补,高能量密度不再是第一追求3月26日,财政部工业和信息化部科技部和发展改革委四部委联合发布了关于进一步完善新能源汽车推广应用财政补贴政策的通知。本次补贴政策主要有以下看点1将安全放在了第一位,技术指标上限不本田地球梦,马自达创驰蓝天,其实真正的厉害角色被忽略了本文章已经通过区块链技术进行版权认证,禁止任何形式的改编转载抄袭,违者追究法律责任近几年,日系车企在全球市场都做的风生水起,其中丰田本田马自达在汽车三大件上的实力都是有目共睹的。特