史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战
史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战
10.2.1)创建Handler:
首先创建Handler类,该类用于接收服务器端发送的数据,这是一个简化的类,只重写了消息读取方法channelRead0、捕捉异常方法exceptionCaught。
客户端的Handler一般继承的是,该类有丰富的方法,心跳、超时检测、连接状态等等。
代码如下:
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
/**
* @Date: 2020/6/1 11:12
* @Description: 通用handler,处理I/O事件
*/
@ChannelHandler.Sharable
public class HandlerClientHello extends SimpleChannelInboundHandler ByteBuf
{
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception
{
/**
* @Description 处理接收到的消息
**/
System.out.println("接收到的消息:"+byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException
{
/**
* @Description 处理I/O事件的异常
**/
cause.printStackTrace();
ctx.close();
}
}
代码说明:
1)@ChannelHandler.Sharable:这个注解是为了线程安全,如果你不在乎是否线程安全,不加也可以;2):这里的类型可以是ByteBuf,也可以是String,还可以是对象,根据实际情况来;3)channelRead0:消息读取方法,注意名称中有个0;4):通道上下文,代指Channel;5):字节序列,通过ByteBuf操作基础的字节数组和缓冲区,因为JDK原生操作字节麻烦、效率低,所以Netty对字节的操作进行了封装,实现了指数级的性能提升,同时使用更加便利;6).UTF_8:这个是JDK原生的方法,用于指定字节数组转换为字符串时的编码格式。10.2.2)创建客户端启动类:
客户端启动类根据服务器端的IP和端口,建立连接,连接建立后,实现消息的双向传输。
代码较简洁,如下:
import com.sun.org.apache.bcel.internal.generic.ATHROW;
import io.netty.*;
import java.net.InetSocketAddress;
/**
* @Date: 2020/6/1 11:24
* @Description: 客户端启动类
*/
public class AppClientHello
{
private final String host;
private fina lint port;
public AppClientHello(String host, int port)
{
this.host = host;
this.port = port;
}
public void run() throws Exception
{
/**
* @Description 配置相应的参数,提供连接到远端的方法
**/
EventLoopGroup group = newNioEventLoopGroup();//I/O线程池
try{
Bootstrap bs = newBootstrap();//客户端辅助启动类
bs.group(group)
.channel(NioSocketChannel.class)//实例化一个Channel
.remoteAddress(newInetSocketAddress(host,port))
.handler(newChannelInitializer SocketChannel ()//进行通道初始化配置
{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception
{
socketChannel.pipeline().addLast(newHandlerClientHello());//添加我们自定义的Handler
}
});
//连接到远程节点;等待连接完成
ChannelFuture future=bs.connect().sync();
//发送消息到服务器端,编码格式是utf-8
future.channel().writeAndFlush(Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8));
//阻塞操作,closeFuture()开启了一个channel的监听器(这期间channel在进行各项工作),直到链路断开
future.channel().closeFuture().sync();
} finally{
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception
{
new AppClientHello("127.0.0.1",18080).run();
}
}
由于代码中已经添加了详尽的注释,这里只对极个别的进行说明:
1):通道Channel的初始化工作,如加入多个handler,都在这里进行;2)bs.connect().sync():这里的sync()表示采用的同步方法,这样连接建立成功后,才继续往下执行;3)pipeline():连接建立后,都会自动创建一个管道pipeline,这个管道也被称为责任链,保证顺序执行,同时又可以灵活的配置各类Handler,这是一个很精妙的设计,既减少了线程切换带来的资源开销、避免好多麻烦事,同时性能又得到了极大增强。10.3 创建服务器端类10.3.1)创建Handler:
和客户端一样,只重写了消息读取方法channelRead(注意这里不是channelRead0)、捕捉异常方法exceptionCaught。
另外服务器端Handler继承的是,而不是,至于这两者的区别,这里不赘述,大家自行百度吧。
代码如下:
import io.netty.*;
/**
* @Date: 2020/6/1 11:47
* @Description: 服务器端I/O处理类
*/
@ChannelHandler.Sharable
public class HandlerServerHello extends ChannelInboundHandlerAdapter
{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
//处理收到的数据,并反馈消息到到客户端
ByteBuf in = (ByteBuf) msg;
System.out.println("收到客户端发过来的消息: "+ in.toString(CharsetUtil.UTF_8));
//写入并发送信息到远端(客户端)
ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是服务端,我已经收到你发送的消息", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
//出现异常的时候执行的动作(打印并关闭通道)
cause.printStackTrace();
ctx.close();
}
}
以上代码很简洁,大家注意和客户端Handler类进行比较。
10.3.2)创建服务器端启动类:
服务器端启动类比客户端启动类稍显复杂一点,先贴出代码如下:
import io.netty.*;
import java.net.InetSocketAddress;
/**
* @Date: 2020/6/1 11:51
* @Description: 服务器端启动类
*/
public class AppServerHello
{
private int port;
public AppServerHello(int port)
{
this.port = port;
}
public void run() throws Exception
{
EventLoopGroup group = newNioEventLoopGroup();//Netty的Reactor线程池,初始化了一个NioEventLoop数组,用来处理I/O操作,如接受新的连接和读/写数据
try{
ServerBootstrap b = newServerBootstrap();//用于启动NIO服务
b.group(group)
.channel(NioServerSocketChannel.class) //通过工厂方法设计模式实例化一个channel
.localAddress(newInetSocketAddress(port))//设置监听端口
.childHandler(newChannelInitializer SocketChannel () {
//ChannelInitializer是一个特殊的处理类,他的目的是帮助使用者配置一个新的Channel,用于把许多自定义的处理类增加到pipline上来
@Override
public void initChannel(SocketChannel ch) throws Exception {//ChannelInitializer 是一个特殊的处理类,他的目的是帮助使用者配置一个新的 Channel。
ch.pipeline().addLast(new HandlerServerHello());//配置childHandler来通知一个关于消息处理的InfoServerHandler实例
}
});
//绑定服务器,该实例将提供有关IO操作的结果或状态的信息
ChannelFuture channelFuture= b.bind().sync();
System.out.println("在"+ channelFuture.channel().localAddress()+"上开启监听");
//阻塞操作,closeFuture()开启了一个channel的监听器(这期间channel在进行各项工作),直到链路断开
channelFuture.channel().closeFuture().sync();
} finally{
group.shutdownGracefully().sync();//关闭EventLoopGroup并释放所有资源,包括所有创建的线程
}
}
public static void main(String[] args) throws Exception
{
new AppServerHello(18080).run();
}
}
代码说明:
1):实际项目中,这里创建两个EventLoopGroup的实例,一个负责接收客户端的连接,另一个负责处理消息I/O,这里为了简单展示流程,让一个实例把这两方面的活都干了;2):通过工厂通过工厂方法设计模式实例化一个channel,这个在大家还没有能够熟练使用Netty进行项目开发的情况下,不用去深究。到这里,我们就把服务器端和客户端都写完了 ,如何运行呢,先在服务器端启动类上右键,点Run 'AppServerHello.main()'菜单运行,见下图。
币圈大佬带你玩赚比特币,如何高回报投资!7年币圈资深老玩家,炒币经验丰富波段和短线策略!2023年真的是币圈大年没有什么好虚的,干就完了!经验丰富的大佬每天分享币圈行情,翻几倍的赚钱机会你准备抓了吗?
七年虚拟货币玩家,如何高回报投z数字货币,离比特币减半倒计时一年半不到,最后一波10~100倍财富回报盛宴,错过了就不再有!
从2013年接触区块链,并且在比特币赚到了一桶金从此一直专研数字货币大牛谈不上,但是也带着很多学生做了几年投咨,很多学员也从中赚一桶金,没错过比特币,没错过以太坊,没错过山寨币,没错过ICO,有着多年数字货币经验!
聪明的人都已经在比特币投.资上赚上几千万,上亿都有了!
欢迎大家来一起交流,互相学习!
史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战
------
延伸阅读:
币圈炒币没有不赚钱的行情、只有不成功的操作
在币圈市场,套牢之后,无论如何处理都是被动的操作,解套固然是投资者必须掌握的基本功,但是投资者更应该把精力放在套牢之前,想办法提高分析技巧和买卖水平,尽可能减少被套的次数,始终占据资金和心态的主动,这才是最重要的。提出了个人的解决办法,希望对广大投资者有所帮助:
1、不服输型
有点明知山有虎偏向虎山行的劲头。好像自己永远没有错误的时候一样。做一个单子扫损接着做,然后接着扫,再做再扫,结果可想而知,账户的资金净值是越来越少,自己的心情是越来越焦急,恨不得做一个单子就把前面的所有损失都捞回来。这样的投资者世明可以很负责的告诉你,你的结局我替你想好了,那就是资金一去不复返,永远不可能从这个市场里面赚到钱。
解决方法:在这个市场中不会可怜不认输的投资者的,那样你就是屡战屡败的代表,认输是为了更好的盈利,别把自己的资金放在水深火热中。
2、逆势加仓型
正所谓聪明反被聪明误。这样的投资者心里的信条是物极必反。常挂在嘴边的话是:都涨成这样了,还能涨到哪里去(都跌成这样了,还能跌到哪里去),结果是单子深深的套在里面,最终的结局就是怀着侥幸的心理等待,最终等来了爆仓的那一刻。
解决方法:可以逆市抢反弹和回调,但是不能逆势做行情,顺其自然,顺势而为。
3、不知深浅型(这里指合约交易)
这样的交易者一般都是在股票市场中有过几年的经验没吃过大亏者,认为自己对技术的分析很厉害了,忽视了合约交易最大的一个特点,那就是资金的杠杆操作,结局就是在股市顺风得水,在币市灰头土脸。
解决方法:把自己的心态放低了,每个投资的品种都有自己的特点,风控要控制好了。
4、做单死抗型
这样的投资者从来就不知道设止损或者说以前设过几次止损而被扫损了,后来就干脆不设,别说,在震荡的行情中还真抗回几张单子,还兴冲冲的告诉别人,我在本周或者本月的正确率是100%。这样的投资者最终的结局就两个字:爆仓。他忽视了一个反向的单边行情就会让他以前N个正确的100%被一个错误的100%搞死。
解决方法:每次做单必须得设止损位,这是没得商量的,不管是什么行情,都得设止损。
5、贪得无厌型
经常重仓操作,甚至满仓梭*,结局依旧爆仓。
解决方法:根据自己的仓位,严格控制风险,轻仓操作。没有风控的投资注定是失败的。
6、赚小亏大型
这样的投资者做单从不抗单,也不锁仓,就是赚钱的单子拿不住,能很快的低头认错也能很快的抬头操作。但是资金总是在慢慢的减少。结局不会是爆仓,大多数是中途退出。
解决方法:做单前,先计划好自己的交易,然后去交易自己的计划,没有特殊的情况不更改自己的计划,可以用移动止损来保住自己已经盈利的部分。
7、抓顶抓底型
抱着让利润最大话的口号,总是幻想着抓个顶和底,一般这样的投资者还有重仓的习惯,短期的结局是一夜暴富和一夜爆负,长期来看结局肯定是爆仓。
解决方法:自己心里必须得清楚,行情没有底和顶的,所以你也没有必要去抓顶和底。假设行情是一条鱼,你所需要做的仅仅是吃鱼身即可,把鱼头和鱼尾留给能吃的动的人吧,鱼身的肉已经够你吃饱了。
8、沉浸过去型
投资者在交易过程中总是沉浸在以往赢利的喜悦里或者是亏损的痛苦中。大多数的交易者还会把这种情绪带到下面的操作中,结果也就不用说了。
解决方法:过去的就是过去的,可以回顾总结经验和教训,但是不能把情绪带到下个单子中,每次做单都是一个新的开始,和过去的单子没什么关系,做好现在,才是最正确的事情。
9、思维单一型
这样的投资者也就是常说的死多头或者死空头。
解决方法:灵活的根据市场的动作更改自己的交易计划,不能一味的抱着一种思想做单。行情本来就是有涨有跌,如果只做一种行情,那就意味着你丧失了一半的赚钱机会,搞不好还会套在里面。
10、节奏踏错型
这样的投资者是反向指标的代言人。总感觉市场是和自己做对的,行情涨他做空,等行情涨的差不多了,自己也承受不了了认赔,那就做涨。结果是刚做上涨行情就开始跌。反反复复的就把自己的资金搞没了。
解决方法:一天中连续两次做单出现错误,就该停止交易了,这就说明,今天的节奏踏错了。自己的情绪在这个时候肯定是不稳定的,继续做下去,肯定还是错误的。
11、激进冒险型
总是喜欢冒很大的风险去赢取蝇头小利,结果肯定是踏上了亏损的道路。
解决方法:时刻告诉自己,钱是自己的,坚决不能让自己的钱处于风险大收益小的行情中,这个时候就是考验耐心的时候了。交流请加笔者!
------------------
推荐阅读: