1. 为什么学习netty

我们已经了解了Socket通信/o/nio/aio编程,对于通信模型已经有了一个初步的认识。其实我们之前所学习的仅仅是-一个模型,如果想把这些真正的用于实际工作中去,那么还需要不断的完善、扩展和优化。比如很经典的Tcp读包写包问题,或者是数据接收的大小,实际的通信读取与应答的处理逻辑等等一些细节问题需要我们认真的去思考,而这些我们都需要大量的时间和经历,以及丰富的经验。所以想学好socket通信不是件容易的事情,那么现在,我们就要学习一门新的技术Netty,我们为什么选择Netty,原因无他,简单!我们再也不必去编写复杂的代码逻辑去实现通信,我们再也不需要去考虑性能问题,不需要考虑编解码问题,半包读写问题等,这些强大的Netty已经帮我们实现好了,我们只需要使用即可。Netty是也就最流行的NIO框架,他的健壮性、功能、性能、可定制性和可扩展性在同类框架都是首屈一指的。它已经得到成百上千的商业商用项目验证,如Hadoop的RPC框架Avro、以及我们之后学习的JMS框架,强大的RocketMQ、还有主流的分布式通信框架Dubbox等等。

认识netty

Netty是基于Java NIO的网络应用框架。Netty是-一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发

网络应用,例如服务器和客户端协议。Netty提供了- -种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty的内部实现是很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦网络应用程序通常需要有较高的可扩展性,无论是Netty还是其他的基于JavaNIO的框架,都会提供可扩展性的解决方案。Netty中-一个关键组成部分是它的异步特性,本章将讨论同步(阻塞)和异步(非阻塞)的10来说明为什么使用异步代码来解决扩展性问题以及如何使用异步。

架构的组成
在这里插入图片描述

为什么Netty使用NIO而不是AIO?

NIO模型
同步非阻塞
NIO有同步阻塞和同步非阻塞两种模式,一般讲的是同步非阻塞,服务器实现模式为一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO模型
异步非阻塞
服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
注:AIO又称为NIO2.0,在JDK7才开始支持。

为什么Netty使用NIO而不是AIO?

Netty不看重Windows上的使用,在Linux系统上,AIO的底层实现仍使用EPOLL,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化
Netty整体架构是reactor模型, 而AIO是proactor模型, 混合在一起会非常混乱,把AIO也改造成reactor模型看起来是把epoll绕个弯又绕回来
AIO还有个缺点是接收数据需要预先分配缓存, 而不是NIO那种需要接收时才需要分配缓存, 所以对连接数量非常大但流量小的情况, 内存浪费很多
Linux上AIO不够成熟,处理回调结果速度跟不到处理需求,比如外卖员太少,顾客太多,供不应求,造成处理速度有瓶颈(待验证)
作者原话:
Not faster than NIO (epoll) on unix systems (which is true)
There is no daragram suppport
Unnecessary threading model (too much abstraction without usage)

2.netty的hello world案例

在学习Netty之前,我们先回顾下FNIO通信步骤:
1创建ServerSocketChannel,.它配置非阻塞模式
2绑定监听,配置TCP参数,录入backlog大小等
3创建-一个独立的I0线程,用于轮询多路复用器Selector
4创建Selector,将之前创建的ServerSocketChannel注册到Selector上,并设置监听标识位
SelectionKey.ACCEPT
5启动I0线程,在循环体中执行Selector.select()方法, 轮询就绪的通道
6当轮询到啦处于就绪的通道时,需要进行判断操作位,如果是ACCEPT状态,说明是新的客户
端接入,则调用accept方法接受新的客户端。
7设置新接入客户端的- -些参数,如非阻塞、并将其通道继续注册到Selector之中,设置监听标
识位等
8如果轮询的通道操作位是READ,则进行读取,构造Buffer对象等
9更细节的还有数据没发送完成继续发送的问题…
ok, -一个简单的NIO服务器端程序,就是如此的复制,下面我们看看Netty完成这件事情需要几个步骤。

安装JDK7
下载地址: http://www.oracle.com/te chnetwork/java/javase/archive-139210.html
下载netty包
下载地址: http://netty.io/
Netty实现通信的步骤:
1 创建两个的NIO线程组,-一个专门用于网络事件处理(接受客户端的连接),另一个
则进行网络通信读写。
存大小
创建一个ServerBootstrap对象,配置Netty的一 系列参数, 例如接受传出数据的缓
3创建一个实际处理数据的类Channellnitializer,进行初始化的准备工作,比如设置
接受传出数据的字符集、格式、已经实际处理数据的接口。
4绑定端口,执行同步阻塞方法等待服务器端启动即可。
如此简单的四个步骤,我们的服务器端就编写完成了,几十行代码就可以把
他完成的健壮、性能稳定,这在我们之前NIO学习的时候是不可能的。
案例:学习网站---- http://ifeve.com/netty5.user.guide/

案例一

server.java

package xxx.netty.test;import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;public class Server {public static void main(String[] args) throws Exception {//NioEventLoopGroup 是用来处理I/O操作的多线程事件循环器//1 第一个线程组 是用于接收Client端连接的EventLoopGroup bossGroup = new NioEventLoopGroup();//2 第二个线程组 是用于实际的业务处理操作的EventLoopGroup workerGroup = new NioEventLoopGroup();//3 创建一个辅助类Bootstrap,就是对我们的Server进行一系列的配置ServerBootstrap b = new ServerBootstrap(); //把俩个工作线程组加入进来b.group(bossGroup, workerGroup)//我要指定使用NioServerSocketChannel这种类型的通道.channel(NioServerSocketChannel.class)//一定要使用 childHandler 去绑定具体的 事件处理器.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(new ServerHandler());}});//绑定指定的端口 进行监听ChannelFuture f = b.bind(8765).sync(); //Thread.sleep(1000000);f.channel().closeFuture().sync();bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}

ServerHandler.java

package xxx.netty.test;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;public class ServerHandler  extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//这里的byteBuf被netty封装过了,不用使用filp它自动回复位//do something msgByteBuf buf = (ByteBuf)msg;byte[] data = new byte[buf.readableBytes()];buf.readBytes(data);String request = new String(data, "utf-8");System.out.println("Server: " + request);//写给客户端String response = "我是反馈的信息";ctx.writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));//.addListener(ChannelFutureListener.CLOSE);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}

client.java

package xxx.netty.test;import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;public class Client {public static void main(String[] args) throws Exception {EventLoopGroup workgroup = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(workgroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(new ClientHandler());}});ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();//bufcf1.channel().writeAndFlush(Unpooled.copiedBuffer("777".getBytes()));cf1.channel().closeFuture().sync();workgroup.shutdownGracefully();}
}

clientHandler.java

package xxx.netty.test;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {try {//do something msgByteBuf buf = (ByteBuf)msg;byte[] data = new byte[buf.readableBytes()];buf.readBytes(data);String request = new String(data, "utf-8");System.out.println("Client: " + request);} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

ClientHandler.java

package xxx.netty.test;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {try {//do something msgByteBuf buf = (ByteBuf)msg;byte[] data = new byte[buf.readableBytes()];buf.readBytes(data);String request = new String(data, "utf-8");System.out.println("Client: " + request);} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

案例二

server.java

package xxx.netty.helloworld;import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;public class Server {public static void main(String[] args) throws Exception {//1 创建线两个程组 //一个是用于处理服务器端接收客户端连接的//一个是进行网络通信的(网络读写的)EventLoopGroup pGroup = new NioEventLoopGroup();EventLoopGroup cGroup = new NioEventLoopGroup();//2 创建辅助工具类,用于服务器通道的一系列配置ServerBootstrap b = new ServerBootstrap();b.group(pGroup, cGroup)		//绑定俩个线程组.channel(NioServerSocketChannel.class)		//指定NIO的模式.option(ChannelOption.SO_BACKLOG, 1024)		//设置tcp缓冲区.option(ChannelOption.SO_SNDBUF, 32*1024)	//设置发送缓冲大小.option(ChannelOption.SO_RCVBUF, 32*1024)	//这是接收缓冲大小.option(ChannelOption.SO_KEEPALIVE, true)	//保持连接.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {//3 在这里配置具体数据接收方法的处理sc.pipeline().addLast(new ServerHandler());}});//4 进行绑定 ChannelFuture cf1 = b.bind(8765).sync();//ChannelFuture cf2 = b.bind(8764).sync();//server端也可以开启多个端口//5 等待关闭cf1.channel().closeFuture().sync();//cf2.channel().closeFuture().sync();释放资源pGroup.shutdownGracefully();cGroup.shutdownGracefully();}
}

ServerHandler.java

package xxx.netty.helloworld;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("server channel active... ");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {ByteBuf buf = (ByteBuf) msg;byte[] req = new byte[buf.readableBytes()];buf.readBytes(req);String body = new String(req, "utf-8");System.out.println("Server :" + body );String response = "进行返回给客户端的响应:" + body ;ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));//.addListener(ChannelFutureListener.CLOSE);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx)throws Exception {System.out.println("读完了");ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable t)throws Exception {ctx.close();}}

client.java

package xxx.netty.helloworld;import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;public class Client {public static void main(String[] args) throws Exception{EventLoopGroup group = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(new ClientHandler());}});ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();//ChannelFuture cf2 = b.connect("127.0.0.1", 8764).sync();//发送消息Thread.sleep(1000);cf1.channel().writeAndFlush(Unpooled.copiedBuffer("777".getBytes()));cf1.channel().writeAndFlush(Unpooled.copiedBuffer("666".getBytes()));//cf2.channel().writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));Thread.sleep(2000);cf1.channel().writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));//cf2.channel().writeAndFlush(Unpooled.copiedBuffer("666".getBytes()));cf1.channel().closeFuture().sync();//cf2.channel().closeFuture().sync();group.shutdownGracefully();}
}

ClientHandler.java

package xxx.netty.helloworld;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {try {ByteBuf buf = (ByteBuf) msg;byte[] req = new byte[buf.readableBytes()];buf.readBytes(req);String body = new String(req, "utf-8");System.out.println("Client :" + body );String response = "收到服务器端的返回信息:" + body;} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();}}

长连接:一个连接一直开着可以多次交互
短连接:一个连接交互完就断开

netty实际应用中的一般如何使用:

将netty程序打包jar,单独运行:
在这里插入图片描述

在maven项目中打包需要配置的pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>netty_deploy</groupId><artifactId>netty_deploy</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>netty_deploy</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><build><!-- 配置文件  --><resources><resource><targetPath>${project.build.directory}/classes</targetPath><directory>src/main/resources</directory><filtering>true</filtering><includes><include>**/*.xml</include><include>**/*.properties</include></includes></resource><resource><targetPath>${project.build.directory}/classes/META-INF</targetPath><directory>src/main/resources</directory><filtering>true</filtering><includes><include>spring-context.xml</include></includes></resource></resources>	<pluginManagement><plugins><!-- 解决Maven插件在Eclipse内执行了一系列的生命周期引起冲突 --><plugin><groupId>org.eclipse.m2e</groupId><artifactId>lifecycle-mapping</artifactId><version>1.0.0</version><configuration><lifecycleMappingMetadata><pluginExecutions><pluginExecution><pluginExecutionFilter><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><versionRange>[2.0,)</versionRange><goals><goal>copy-dependencies</goal></goals></pluginExecutionFilter><action><ignore /></action></pluginExecution></pluginExecutions></lifecycleMappingMetadata></configuration></plugin></plugins></pluginManagement><plugins><!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><configuration><classesDirectory>target/classes/</classesDirectory><archive><manifest><mainClass>tpri.mina.execute.Main</mainClass><!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 --><useUniqueVersions>false</useUniqueVersions><addClasspath>true</addClasspath><classpathPrefix>lib/</classpathPrefix></manifest><manifestEntries><Class-Path>.</Class-Path></manifestEntries></archive></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><executions><execution><id>copy-dependencies</id><phase>package</phase><goals><goal>copy-dependencies</goal></goals><configuration><type>jar</type><includeTypes>jar</includeTypes><useUniqueVersions>false</useUniqueVersions><outputDirectory>${project.build.directory}/lib</outputDirectory></configuration></execution></executions></plugin></plugins></build><dependencies> 	    </dependencies>
</project>

1.指定main程序类
2.生成lib
3.指定依赖jar在lib下路径(这个maven的pom代码百度)

3.关于拆包粘包问题

熟悉tcp编程的可能都知道,无论是服务器端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包/拆包机制。
TCP是一个“流"协议,所谓流就是没有界限的遗传数据。大家可以想象下如果河里的水就好比数据,他们是连成- -片的,没有分界线,TCP底层并不了解上层的业务数据具体的含义,它会根据TCP缓冲区的实际情况进行包的划分,也就是说,在业务上,我们一个完整的包可能会被TCP分成多个包进行发送,也可能把多个小包封装成-一个大的数据包发送出去,这就是所谓的TCP粘包、拆包问题。分析TCP粘包、拆包问题的产生原因:
1应用程序write写入的字节大小大于套接口发送缓冲区的大小
2进行MSS大小的TCP分段
3以太网帧的payload大于MTU进行IP分片

流数据的传输处理
一个小的Socket Buffer问题
在基于流的传输里比如TCP/IP,接收到的数据会先被存储到一个socket接收缓冲里。不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列。即使你发送了2个独立的数据包,操作系统也不会作为2个消息处理而仅仅是作为一连串的字节而言。因此这是不能保证你远程写入的数据就会准确地读取。举个例子,让我们假设操作系统的TCP/TP协议栈已经接收了3个数据包:

netty5_1.png

由于基于流传输的协议的这种普通的性质,在你的应用程序里读取数据的时候会有很高的可能性被分成下面的片段。

netty5_2.png

因此,一个接收方不管他是客户端还是服务端,都应该把接收到的数据整理成一个或者多个更有意思并且能够让程序的业务逻辑更好理解的数据。在上面的例子中,接收到的数据应该被构造成下面的格式:

netty5_3.png

再如:

客户端连续发三个:hello netty
在这里插入图片描述
server端看到的三个连在一起一个字符串,对接受到的数据内容应该是三个分开的hello netty!的字符串,显然这个不是我们想象的结果。

在这里插入图片描述
拆包粘包解决方案:
粘包拆包问题的解决方案,根据业界主流协议,的有三种方案:
1消息定长,例如每个报文的大小固定为200个字节,如果不够,空位补空格;
2在包尾部增加特殊字符进行分割,例如加回车等
3讲消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,
然后进行业务逻辑的处理

1分隔符类DelimiterBasedFrameDecoder (自定义分隔符)
2 FixedLengthFrameDecoder (定长)

1.分隔符类

案例:
server.java

package xxx.netty.ende1;import java.nio.ByteBuffer;import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;public class Server {public static void main(String[] args) throws Exception{//1 创建2个线程,一个是负责接收客户端的连接。一个是负责进行数据传输的EventLoopGroup pGroup = new NioEventLoopGroup();EventLoopGroup cGroup = new NioEventLoopGroup();//2 创建服务器辅助类ServerBootstrap b = new ServerBootstrap();b.group(pGroup, cGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).option(ChannelOption.SO_SNDBUF, 32*1024).option(ChannelOption.SO_RCVBUF, 32*1024).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {//设置特殊分隔符ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));//设置字符串形式的解码sc.pipeline().addLast(new StringDecoder());sc.pipeline().addLast(new ServerHandler());}});//4 绑定连接ChannelFuture cf = b.bind(8765).sync();//等待服务器监听端口关闭cf.channel().closeFuture().sync();pGroup.shutdownGracefully();cGroup.shutdownGracefully();}}

ServerHandler.java

package xxx.netty.ende1;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println(" server channel active... ");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String request = (String)msg;System.out.println("Server :" + msg);String response = "服务器响应:" + msg + "$_";ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {ctx.close();}
}

client.java

package xxx.netty.ende1;import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;public class Client {public static void main(String[] args) throws Exception {EventLoopGroup group = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {//ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));sc.pipeline().addLast(new StringDecoder());sc.pipeline().addLast(new ClientHandler());}});ChannelFuture cf = b.connect("127.0.0.1", 8765).sync();cf.channel().writeAndFlush(Unpooled.wrappedBuffer("bbbb$_".getBytes()));cf.channel().writeAndFlush(Unpooled.wrappedBuffer("cccc$_".getBytes()));//等待客户端端口关闭cf.channel().closeFuture().sync();group.shutdownGracefully();}
}

ClientHandler.java

package xxx.netty.ende1;import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client channel active... ");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {try {String response = (String)msg;System.out.println("Client: " + response);} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}}

在这里插入图片描述

2.定长方式

Server.java

package xxx.netty.ende2;import java.nio.ByteBuffer;import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;public class Server {public static void main(String[] args) throws Exception{//1 创建2个线程,一个是负责接收客户端的连接。一个是负责进行数据传输的EventLoopGroup pGroup = new NioEventLoopGroup();EventLoopGroup cGroup = new NioEventLoopGroup();//2 创建服务器辅助类ServerBootstrap b = new ServerBootstrap();b.group(pGroup, cGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).option(ChannelOption.SO_SNDBUF, 32*1024).option(ChannelOption.SO_RCVBUF, 32*1024).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {//设置定长字符串接收sc.pipeline().addLast(new FixedLengthFrameDecoder(5));//设置字符串形式的解码sc.pipeline().addLast(new StringDecoder());sc.pipeline().addLast(new ServerHandler());}});//4 绑定连接ChannelFuture cf = b.bind(8765).sync();//等待服务器监听端口关闭cf.channel().closeFuture().sync();pGroup.shutdownGracefully();cGroup.shutdownGracefully();}}

ServerHandler.java

package xxx.netty.ende2;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println(" server channel active... ");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String request = (String)msg;System.out.println("Server :" + msg);String response =  request ;ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {}
}

Client.java

package xxx.netty.ende2;import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;public class Client {public static void main(String[] args) throws Exception {EventLoopGroup group = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(new FixedLengthFrameDecoder(5));sc.pipeline().addLast(new StringDecoder());sc.pipeline().addLast(new ClientHandler());}});ChannelFuture cf = b.connect("127.0.0.1", 8765).sync();cf.channel().writeAndFlush(Unpooled.wrappedBuffer("aaaaabbbbb".getBytes()));cf.channel().writeAndFlush(Unpooled.copiedBuffer("ccccccc".getBytes()));//等待客户端端口关闭cf.channel().closeFuture().sync();group.shutdownGracefully();}
}

ClientHandler.java

package xxx.netty.ende2;import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class ClientHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client channel active... ");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String response = (String)msg;System.out.println("Client: " + response);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {}}

定长虽然可以实现,但是分割符才是最常用的。

4.netty编解码技术

编解码技术,说白了就是java序列化技术,序列化目的就两个,第- -进行网络传输,第二对象持久化。虽然我们可以使用java进行对象序列化,netty 去传输,但是java序列化的硬伤太多,比如java序列化没法跨语言、序列化后码流太大、序列化性能太低
等等…
主流的编解码框架:|
JBoss的Marshalling包
google的Protobuf
基于Protobuf的Kyro
MessagePack框架

我们使用JBoss的Marshalling来解析,使用之前先认识下java解压压缩的工具类
传送文件解压缩的工具类案例:
GzipUtils.java

package xxx.utils;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;public class GzipUtils {public static byte[] gzip(byte[] data) throws Exception{ByteArrayOutputStream bos = new ByteArrayOutputStream();GZIPOutputStream gzip = new GZIPOutputStream(bos);gzip.write(data);gzip.finish();gzip.close();byte[] ret = bos.toByteArray();bos.close();return ret;}public static byte[] ungzip(byte[] data) throws Exception{ByteArrayInputStream bis = new ByteArrayInputStream(data);GZIPInputStream gzip = new GZIPInputStream(bis);byte[] buf = new byte[1024];int num = -1;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((num = gzip.read(buf, 0 , buf.length)) != -1 ){bos.write(buf, 0, num);}gzip.close();bis.close();byte[] ret = bos.toByteArray();bos.flush();bos.close();return ret;}public static void main(String[] args) throws Exception{//读取文件String readPath = System.getProperty("user.dir") + File.separatorChar + "sources" +  File.separatorChar + "006.jpg";File file = new File(readPath);  FileInputStream in = new FileInputStream(file);  byte[] data = new byte[in.available()];  in.read(data);  in.close();  System.out.println("文件原始大小:" + data.length);//测试压缩byte[] ret1 = GzipUtils.gzip(data);System.out.println("压缩之后大小:" + ret1.length);byte[] ret2 = GzipUtils.ungzip(ret1);System.out.println("还原之后大小:" + ret2.length);//写出文件String writePath = System.getProperty("user.dir") + File.separatorChar + "receive" +  File.separatorChar + "006.jpg";FileOutputStream fos = new FileOutputStream(writePath);fos.write(ret2);fos.close();    	}}

TestSystemProperty.java

package xxx.utils;public class TestSystemProperty {public static void main(String[] args) {System.out.println("java版本号:" + System.getProperty("java.version")); // java版本号System.out.println("Java提供商名称:" + System.getProperty("java.vendor")); // Java提供商名称System.out.println("Java提供商网站:" + System.getProperty("java.vendor.url")); // Java提供商网站System.out.println("jre目录:" + System.getProperty("java.home")); // Java,哦,应该是jre目录System.out.println("Java虚拟机规范版本号:" + System.getProperty("java.vm.specification.version")); // Java虚拟机规范版本号System.out.println("Java虚拟机规范提供商:" + System.getProperty("java.vm.specification.vendor")); // Java虚拟机规范提供商System.out.println("Java虚拟机规范名称:" + System.getProperty("java.vm.specification.name")); // Java虚拟机规范名称System.out.println("Java虚拟机版本号:" + System.getProperty("java.vm.version")); // Java虚拟机版本号System.out.println("Java虚拟机提供商:" + System.getProperty("java.vm.vendor")); // Java虚拟机提供商System.out.println("Java虚拟机名称:" + System.getProperty("java.vm.name")); // Java虚拟机名称System.out.println("Java规范版本号:" + System.getProperty("java.specification.version")); // Java规范版本号System.out.println("Java规范提供商:" + System.getProperty("java.specification.vendor")); // Java规范提供商System.out.println("Java规范名称:" + System.getProperty("java.specification.name")); // Java规范名称System.out.println("Java类版本号:" + System.getProperty("java.class.version")); // Java类版本号System.out.println("Java类路径:" + System.getProperty("java.class.path")); // Java类路径System.out.println("Java lib路径:" + System.getProperty("java.library.path")); // Java lib路径System.out.println("Java输入输出临时路径:" + System.getProperty("java.io.tmpdir")); // Java输入输出临时路径System.out.println("Java编译器:" + System.getProperty("java.compiler")); // Java编译器System.out.println("Java执行路径:" + System.getProperty("java.ext.dirs")); // Java执行路径System.out.println("操作系统名称:" + System.getProperty("os.name")); // 操作系统名称System.out.println("操作系统的架构:" + System.getProperty("os.arch")); // 操作系统的架构System.out.println("操作系统版本号:" + System.getProperty("os.version")); // 操作系统版本号System.out.println("文件分隔符:" + System.getProperty("file.separator")); // 文件分隔符System.out.println("路径分隔符:" + System.getProperty("path.separator")); // 路径分隔符System.out.println("直线分隔符:" + System.getProperty("line.separator")); // 直线分隔符System.out.println("操作系统用户名:" + System.getProperty("user.name")); // 用户名System.out.println("操作系统用户的主目录:" + System.getProperty("user.home")); // 用户的主目录System.out.println("当前程序所在目录:" + System.getProperty("user.dir")); // 当前程序所在目录}
}
  • java 中 byte[]、File、InputStream 互相转换:将file、fileinputstream转换为byte数组
    使用available():
1、将File、FileInputStream 转换为byte数组:File file = new File("test.txt");InputStream input = new FileInputStream(file);byte[] byt = new byte[input.available()];input.read(byt);2、将byte数组转换为InputStream:byte[] byt = new byte[1024];InputStream input = new ByteArrayInputStream(byt);3、将byte数组转换为File:File file = new File('');OutputStream output = new FileOutputStream(file);BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);bufferedOutput.write(byt);

下面是编解码的具体案例:
Req.java

package xxx.netty.serial;import java.io.Serializable;public class Req implements Serializable{private static final long  SerialVersionUID = 1L;private String id ;private String name ;private String requestMessage ;private byte[] attachment;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRequestMessage() {return requestMessage;}public void setRequestMessage(String requestMessage) {this.requestMessage = requestMessage;}public byte[] getAttachment() {return attachment;}public void setAttachment(byte[] attachment) {this.attachment = attachment;}}

Resp.java

package xxx.netty.serial;import java.io.Serializable;public class Resp implements Serializable{private static final long serialVersionUID = 1L;private String id;private String name;private String responseMessage;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getResponseMessage() {return responseMessage;}public void setResponseMessage(String responseMessage) {this.responseMessage = responseMessage;}}

Server.java

package bhz.netty.serial;import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;public class Server {public static void main(String[] args) throws Exception{EventLoopGroup pGroup = new NioEventLoopGroup();EventLoopGroup cGroup = new NioEventLoopGroup();ServerBootstrap b = new ServerBootstrap();b.group(pGroup, cGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)//设置日志.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {protected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());sc.pipeline().addLast(new ServerHandler());}});ChannelFuture cf = b.bind(8765).sync();cf.channel().closeFuture().sync();pGroup.shutdownGracefully();cGroup.shutdownGracefully();}
}

ServerHandler.java

package xxx.netty.serial;import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;import java.io.File;
import java.io.FileOutputStream;import bhz.utils.GzipUtils;public class ServerHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {Req req = (Req)msg;System.out.println("Server : " + req.getId() + ", " + req.getName() + ", " + req.getRequestMessage());byte[] attachment = GzipUtils.ungzip(req.getAttachment());String path = System.getProperty("user.dir") + File.separatorChar + "receive" +  File.separatorChar + "001.jpg";FileOutputStream fos = new FileOutputStream(path);fos.write(attachment);fos.close();Resp resp = new Resp();resp.setId(req.getId());resp.setName("resp" + req.getId());resp.setResponseMessage("响应内容" + req.getId());ctx.writeAndFlush(resp);//.addListener(ChannelFutureListener.CLOSE);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}}

Client.java

package xxx.netty.serial;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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 java.io.File;
import java.io.FileInputStream;import bhz.utils.GzipUtils;public class Client {public static void main(String[] args) throws Exception{EventLoopGroup group = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());sc.pipeline().addLast(new ClientHandler());}});ChannelFuture cf = b.connect("127.0.0.1", 8765).sync();for(int i = 0; i < 5; i++ ){Req req = new Req();req.setId("" + i);req.setName("pro" + i);req.setRequestMessage("数据信息" + i);	String path = System.getProperty("user.dir") + File.separatorChar + "sources" +  File.separatorChar + "001.jpg";File file = new File(path);FileInputStream in = new FileInputStream(file);  byte[] data = new byte[in.available()];  in.read(data);  in.close(); req.setAttachment(GzipUtils.gzip(data));cf.channel().writeAndFlush(req);}cf.channel().closeFuture().sync();group.shutdownGracefully();}
}

ClientHandler.java

package xxx.netty.serial;import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;public class ClientHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {try {Resp resp = (Resp)msg;System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " + resp.getResponseMessage());			} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}}

MarshallingCodeCFactory.java

package xxx.netty.serial;import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallingDecoder;
import io.netty.handler.codec.marshalling.MarshallingEncoder;
import io.netty.handler.codec.marshalling.UnmarshallerProvider;import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;/*** Marshalling工厂* @author(alienware)* @since 2014-12-16*/
public final class MarshallingCodeCFactory {/*** 创建Jboss Marshalling解码器MarshallingDecoder* @return MarshallingDecoder*/public static MarshallingDecoder buildMarshallingDecoder() {//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");//创建了MarshallingConfiguration对象,配置了版本号为5 final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);//根据marshallerFactory和configuration创建providerUnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);return decoder;}/*** 创建Jboss Marshalling编码器MarshallingEncoder* @return MarshallingEncoder*/public static MarshallingEncoder buildMarshallingEncoder() {final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组MarshallingEncoder encoder = new MarshallingEncoder(provider);return encoder;}
}

5. netty的upd

(自己看实际工作很少使用)
server.java

package xxx.netty.udp;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;public class Server {public void run(int port) throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true).handler(new ServerHandler());b.bind(port).sync().channel().closeFuture().await();} finally {group.shutdownGracefully();}}public static void main(String[] args) throws Exception {new Server().run(8765);new Server().run(8764);}
}

ServerHandler.java

package xxx.netty.udp;import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.ThreadLocalRandom;public class ServerHandler extendsSimpleChannelInboundHandler<DatagramPacket> {// 谚语列表private static final String[] DICTIONARY = { "只要功夫深,铁棒磨成针。","旧时王谢堂前燕,飞入寻常百姓家。", "洛阳亲友如相问,一片冰心在玉壶。","一寸光阴一寸金,寸金难买寸光阴。","老骥伏枥,志在千里。烈士暮年,壮心不已!"};private String nextQuote() {int quoteId = ThreadLocalRandom.current().nextInt(DICTIONARY.length);return DICTIONARY[quoteId];}@Overridepublic void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet)throws Exception {String req = packet.content().toString(CharsetUtil.UTF_8);System.out.println(req);if ("谚语字典查询?".equals(req)) {ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("谚语查询结果: " + nextQuote(),CharsetUtil.UTF_8), packet.sender()));}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();cause.printStackTrace();}
}

cilent.java

package xxx.netty.udp;import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;import java.net.InetSocketAddress;public class Client {public void run(int port) throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true).handler(new ClientHandler());Channel ch = b.bind(0).sync().channel();// 向网段内的所有机器广播UDP消息ch.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("谚语字典查询?", CharsetUtil.UTF_8), new InetSocketAddress("255.255.255.255", port))).sync();if (!ch.closeFuture().await(15000)) {System.out.println("查询超时!");}} finally {group.shutdownGracefully();}}public static void main(String[] args) throws Exception {new Client().run(8765);}
}

ClientHandler.java

package xxx.netty.udp;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;public class ClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {@Overridepublic void messageReceived(ChannelHandlerContext ctx, DatagramPacket msg)throws Exception {String response = msg.content().toString(CharsetUtil.UTF_8);if (response.startsWith("谚语查询结果: ")) {System.out.println(response);ctx.close();}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {cause.printStackTrace();ctx.close();}
}

6.netty项目demo

我们需要了解下在真正项目应用中如何去考虐Netty的使用,大体上对于-些参数设置都是根据
服务器性能决定的。这个不是最主要的。
我们需要考虑的问题是两台机器(甚至多台)使用Netty的怎样进行通信,我个人大体上把他分
为三种:
1第一种,使用长连接通道不断开的形式进行通信,也就是服务器和客户端的通道一直处于
开启状态,如果服务器性能足够好,并且我们的客户端数量也比较少的情况下,我还是推荐这种
方式的.
2第二种,一次性批量提交数据,采用短连接方式。也就是我们会把数据保存在本地临时缓
冲区或者临时表里,当达到临界值时进行一次性批量提交, 又或者根据定时任务轮询提交,这种
情况弊端是做不到实时性传输,在对实时性不高的应用程序中可以推荐使用.
3第三种,我们可以使用一-种特殊的长连接,在指定某- -时间之内,服务器与某台客户端没
有任何通信,则断开连接。下次连接则是客户端向服务器发送请求的时候,再次建立连接。但是
这种模式我们需要考虑2个因素:
1如何在超时(即服务器和客户端没有任何通信)后关闭通道?关闭通道后我们又如何
再次建立连接?
2客户端宕机时,我们无需考虑,下次客户端重启之后我们就可以与服务器建立连接,
但是服务器宕机时,我们的客户端如何与服务器进行连接呢?

server.java

package xxx.netty.runtime;import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;public class Server {public static void main(String[] args) throws Exception{EventLoopGroup pGroup = new NioEventLoopGroup();EventLoopGroup cGroup = new NioEventLoopGroup();ServerBootstrap b = new ServerBootstrap();b.group(pGroup, cGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)//设置日志.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {protected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());sc.pipeline().addLast(new ReadTimeoutHandler(5)); sc.pipeline().addLast(new ServerHandler());}});ChannelFuture cf = b.bind(8765).sync();cf.channel().closeFuture().sync();pGroup.shutdownGracefully();cGroup.shutdownGracefully();}
}

ServerHandler.java

package xxx.netty.runtime;import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter{@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {Request request = (Request)msg;System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " + request.getRequestMessage());Response response = new Response();response.setId(request.getId());response.setName("response" + request.getId());response.setResponseMessage("响应内容" + request.getId());ctx.writeAndFlush(response);//.addListener(ChannelFutureListener.CLOSE);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}	
}

client.java

package bhz.netty.runtime;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;import java.util.concurrent.TimeUnit;/*** Best Do It*/
public class Client {private static class SingletonHolder {static final Client instance = new Client();}public static Client getInstance(){return SingletonHolder.instance;}private EventLoopGroup group;private Bootstrap b;private ChannelFuture cf ;private Client(){group = new NioEventLoopGroup();b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception {sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());//超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)sc.pipeline().addLast(new ReadTimeoutHandler(5)); sc.pipeline().addLast(new ClientHandler());}});}public void connect(){try {this.cf = b.connect("127.0.0.1", 8765).sync();System.out.println("远程服务器已经连接, 可以进行数据交换..");				} catch (Exception e) {e.printStackTrace();}}public ChannelFuture getChannelFuture(){if(this.cf == null){this.connect();}if(!this.cf.channel().isActive()){this.connect();}return this.cf;}public static void main(String[] args) throws Exception{final Client c = Client.getInstance();//c.connect();ChannelFuture cf = c.getChannelFuture();for(int i = 1; i <= 3; i++ ){Request request = new Request();request.setId("" + i);request.setName("pro" + i);request.setRequestMessage("数据信息" + i);cf.channel().writeAndFlush(request);TimeUnit.SECONDS.sleep(4);}cf.channel().closeFuture().sync();new Thread(new Runnable() {@Overridepublic void run() {try {System.out.println("进入子线程...");ChannelFuture cf = c.getChannelFuture();System.out.println(cf.channel().isActive());System.out.println(cf.channel().isOpen());//再次发送数据Request request = new Request();request.setId("" + 4);request.setName("pro" + 4);request.setRequestMessage("数据信息" + 4);cf.channel().writeAndFlush(request);					cf.channel().closeFuture().sync();System.out.println("子线程结束.");} catch (InterruptedException e) {e.printStackTrace();}}}).start();System.out.println("断开连接,主线程结束..");}	
}

cilentHandler.java

MarshallingCodeCFactory.java

package xxx.netty.runtime;import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallerProvider;
import io.netty.handler.codec.marshalling.MarshallingDecoder;
import io.netty.handler.codec.marshalling.MarshallingEncoder;
import io.netty.handler.codec.marshalling.UnmarshallerProvider;import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;/*** Marshalling工厂* @author(alienware)* @since 2014-12-16*/
public final class MarshallingCodeCFactory {/*** 创建Jboss Marshalling解码器MarshallingDecoder* @return MarshallingDecoder*/public static MarshallingDecoder buildMarshallingDecoder() {//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");//创建了MarshallingConfiguration对象,配置了版本号为5 final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);//根据marshallerFactory和configuration创建providerUnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024);return decoder;}/*** 创建Jboss Marshalling编码器MarshallingEncoder* @return MarshallingEncoder*/public static MarshallingEncoder buildMarshallingEncoder() {final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组MarshallingEncoder encoder = new MarshallingEncoder(provider);return encoder;}
}

request.java

package xxx.netty.runtime;import java.io.Serializable;public class Request implements Serializable{private static final long  SerialVersionUID = 1L;private String id ;private String name ;private String requestMessage ;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRequestMessage() {return requestMessage;}public void setRequestMessage(String requestMessage) {this.requestMessage = requestMessage;}}

response.java

package xxx.netty.runtime;import java.io.Serializable;public class Response implements Serializable{private static final long serialVersionUID = 1L;private String id;private String name;private String responseMessage;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getResponseMessage() {return responseMessage;}public void setResponseMessage(String responseMessage) {this.responseMessage = responseMessage;}}
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. CANoe隐藏属性——Multi CANoe

    CANoe的简单功能估计大家都用到滚瓜烂熟了,那就趁机认识一下Multi CANoe吧!Multi CANoe是CANoe的一种特殊操作模式。它允许多个CANoe实例在不同的计算机上同时运行,所有CANoe实例可以通过Vector硬件同步功能来达到时间同步,每个CANoe实例都有自己的用户操作界面,参考如下示…...

    2024/4/30 13:12:59
  2. 用爬虫获取新冠疫情历史数据

    之前开源的新冠疫情历史数据见github仓库,有好多人问我这些数据是怎么获取的,因为最近一个月一直在忙创新实训的事情,所以也一直没有时间把博客写出来,现在博客写完了,不过是放在我自己搭的博客上的,在这里推一波hh。 博客链接:访问入口1 访问入口2 第一个是部署在verce…...

    2024/4/30 16:37:11
  3. kafka集群磁盘满警告,新增kafka节点,重新分配partition

    本文参考了网上部分文章,并进行了说明和归纳,详情请查看参考。官方文档参考:https://cwiki.apache.org/confluence/display/KAFKA/Replication+toolskafka环境中机器磁盘告警很容易出现,原因可能是某一个topic的partition为1(或者partition不足导致的),只往一台机器上写数…...

    2024/4/29 10:09:17
  4. 新版本jdk(9、11、12、13、14)特性

    目录背景jdk9新特性目录结构的改变模块化系统要解决的问题概念实现目标示例jShell命令多版本兼容jar包接口中的私有方法钻石操作符(泛型)的升级try语句的升级下划线命名标识符的限制String存储结构的变化快速创建只读集合增强的流apitakeWhiledropWhileof()方法和ofNullable()方…...

    2024/5/2 14:41:29
  5. 分布式一致性算法——Paxos原理与推导过程

    Paxos算法在分布式领域具有非常重要的地位。但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难。网上有很多讲解Paxos算法的文章,但是质量参差不齐。看了很多关于Paxos的资料后发现,学习Paxos最好的资料是论文《Paxos Made Simple》,其次是中、英文版维基百科对…...

    2024/4/30 12:18:43
  6. 网络爬虫和爬虫代理之间的关系

    网络爬虫 网络爬虫也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理。在大数据时代,信息的采集是一项重要的工作,如果单纯靠人力进行信息采集,不仅低效繁琐,搜集的成本也会提高。 此时,我们可以使用网络爬虫对数据信息进行自动采集,比如应用于搜…...

    2024/5/1 10:55:29
  7. java实现遍历文件夹下的文件及文件夹

    package com.gblfy.test;import java.io.File; import java.util.ArrayList; import java.util.LinkedList; import java.util.List;/*** 文件常用工具类** @author gblfy* @description FileUtil* @date 2020/07/03 17:05*/ public class FileUtil {/*** 遍历目录下面的文件夹…...

    2024/5/1 5:38:40
  8. SpringBoot-03自动配置原理

    SpringBoot-03自动配置原理 根据当前不同的条件判断,决定这个配置类是否生效!1.一但这个配置类生效;这个配置类就会给容器中添加各种组件; 2.这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的; 3.所有在配置文件中能配置的属性…...

    2024/4/20 12:56:32
  9. linux下安装nvm

    nvm是nodejs的版本管理工具,用于切换nodejs版本在windows下使用exe安装包安装,linux下则使用脚本安装1.下载安装脚本https://github.com/nvm-sh/nvm/blob/master/install.sh2.运行安装脚本czy@Mint ~/workspace/gitee/nvm $ ./install.sh => Downloading nvm from git to…...

    2024/4/20 16:18:37
  10. LeetCode刷题---无重复字符的最长子串(3)

    题目 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。 示例 …...

    2024/4/16 13:36:14
  11. webpack 配置 alias

    webpack 配置 alias 后很方便,有时有我们项目比较大,比较复杂的时候尤为重要 const path = require(path); const resolvePath = relativePath => path.resolve(process.cwd(), relativePath); { .... alias: {@: resolvePath(src),@common: ../../common,},}...

    2024/4/1 0:28:03
  12. 我要开始写博客啦!!

    我要开始写博客啦!!一个简单的自我介绍 一个简单的自我介绍 20届研一,刚刚开始,和老师交流后准备研究车联网方向,现在开始读论文。准备写博客督促自己学习进度,练习内化输出知识。...

    2024/4/16 13:35:13
  13. HTML DIV 多层显示测试

    <!doctype html> <html> <head><title>table contenteditable</title><style type="text/css">.bg_img {/*相对位置*/position: relative;width: 625px;height: 352px; }.ms {/*绝对位置*/position: absolute;background: #a823…...

    2024/4/19 17:16:31
  14. 制作3389端口修改工具心得1

    设置思路人工修改方法c++操作注册表的方法c++开/关远程桌面的方法 人工修改方法 1、修改注册表 (1)HKEY_LOCAL_MACHINE\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp中的PortNumber (2)HKEY_LOCAL_MACHINE\SYSTEM\\CurrentControlSet\\Cont…...

    2024/4/18 2:42:55
  15. YARN工作流程

    自己画的 有错误请大家指出YARN的运行流程(工作机制) 1.clinet提交程序,向RM申请一个唯一的jobid 2.RM返回一个jobid,并且返回程序提交资源的路径发送给客户端 3.Client端将运行作业所需要的资源(如:jar包,配置文件,切片信息等)向指定的hdfs路径上传(注意:这个hdfs的路…...

    2024/5/2 16:34:35
  16. PAT甲级 A1096

    PAT甲级 A1096 题目详情 1096 Consecutive Factors (20分) Among all the factors of a positive integer N, there may exist several consecutive numbers. For example, 630 can be factored as 3567, where 5, 6, and 7 are the three consecutive numbers. Now given any …...

    2024/4/16 13:36:19
  17. RabbitMQ的应用场景以及基本原理介绍

    RabbitMQ的应用场景以及基本原理介绍 1.背景 RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现。 2.应用场景 2.1异步处理 场景说明:用户注册后,需要发注册邮件和注册短信,传统的做法有两种1.串行的方式;2.并行的方式 (1)串行方式:将注册信息写入数据库后…...

    2024/5/2 1:52:13
  18. 高等数学知识点汇总

    第一章 函数、极限与连续 1、函数的有界性2、极限的定义(数列、函数)3、极限的性质(有界性、保号性)4、极限的计算(重点)(四则运算、等价无穷小替换、洛必达法则、泰勒公式、重要极限、单侧极限、夹逼定理及定积分定义、单调有界必有极限定理)5、函数的连续性6、间断点的类型7、…...

    2024/4/16 13:37:20
  19. windows10 下用 docker 打包程序

    确定项目包和支持包 先确定项目包的内容,并导出所需要的包,放在项目目录下 pip freeze > requirements.txt创建 Dockerfile 然后与 default 同级创建 Dockerfile# 基于的基础镜像 FROM python:3.6.5#代码添加到 default_docker 文件夹 ADD ./default /default_docker# 设置…...

    2024/4/17 7:03:54
  20. 新增端口用于ssh

    内部服务器新增端口修改sshd_config配置文件vi /etc/ssh/sshd_config找到Port和ListenAddress的配置区域,进行如下修改Port 22 Port 24922 Port 18622说明:打开22注释以防配置发生意外,无法连接服务器重启sshd服务 systemctl restart sshd查看端口开放状态 netstat -nap | grep…...

    2024/5/2 16:20:56

最新文章

  1. 探索洗牌算法的魅力与杨辉三角的奥秘:顺序表的实际运用

    目录 目录 前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 洗牌算法 准备工作 买一副牌 洗牌 发牌 测试整体 &#x1f3af;&#x1f3af;很重要的一点 杨辉三角 总结 前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ …...

    2024/5/2 16:43:28
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. WKWebView的使用

    一、简介 在iOS中&#xff0c;WKWebView是WebKit框架提供的一个用于展示网页内容的控件&#xff0c;相比UIWebView有更好的性能和功能。 以下是在iOS中使用WKWebView的基本步骤&#xff1a; 1.1 导入WebKit框架 import WebKit1.2 创建WKWebView实例 let webView WKWebVie…...

    2024/5/2 7:33:06
  4. 【Angular】什么是Angular中的APP_BASE_HREF

    1 概述: 在这篇文章中&#xff0c;我们将看到Angular 10中的APP_BASE_HREF是什么以及如何使用它。 APP_BASE_HREF为当前页面的基础href返回一个预定义的DI标记。 APP_BASE_HREF是应该被保留的URL前缀。 2 语法: provide: APP_BASE_HREF, useValue: /gfgapp3 步骤: 在app.m…...

    2024/5/1 14:04:25
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/2 9:28:15
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57