在网上学了好几个netty入门,后来去bilibili学过来的入门。
学习链接:https://www.bilibili.com/video/av15277109/
个人理解:netty好多地方可以使用,是基于NIO技术的框架实现,我理解的NIO(new IO),是一种非阻塞式IO,使用单线程或多线程处理多并发业务,使用selector获取每条线程的信息。无需全部轮询线程后才知道那个线程空闲才去执行,而且使用的是ByteBuf这种缓存区类型,读到文章有说,本来本地数据是从硬盘到电脑缓存再到程序缓存的多次拷贝数据,导致数据传输缓慢,而使用NIO,可以在中间开辟空间,直接使用channel 读取到公共部分缓冲区,实现零拷贝,我理解的是ByteBuf这种东西,NIO还没去看,见谅。
附上netty代码:
下面是使用netty做的网络通讯,还没使用scanner做出聊天室效果,只是小demo
服务端类
package com.java.Olym.netty;
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 NettyServer {
public void bind(int port) throws Exception{
EventLoopGroup bgroup = new NioEventLoopGroup();//在外等待连接的通道
EventLoopGroup pgroup = new NioEventLoopGroup();//与client连接的通道
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bgroup,pgroup)
.channel(NioServerSocketChannel.class)//server通道
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO))//设置日志
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ServerHandler());//设置到业务处理的handler
ch.pipeline().addLast(new ReadTimeoutHandler(5));//设置超时时间断开设置
}
});
ChannelFuture cf = b.bind(port).sync();//绑定端口
cf.channel().closeFuture().sync();
}finally{
//必须关闭的两个通道,会有数据在里面堆积
bgroup.shutdownGracefully();
pgroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8089;
new NettyServer().bind(port);//启动server服务
}
}
server的业务处理类
package com.java.Olym.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf)msg;//netty socket通信使用ByteBuf
System.out.println("The server recive massage:"+buf.toString());
ctx.writeAndFlush(buf);//写出消息并刷新出去消息 到客户端
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端类
package com.java.Olym.netty;
import java.net.InetSocketAddress;
import ch.qos.logback.core.util.TimeUtil;
import io.netty.bootstrap.Bootstrap;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
public class NettyClient {
private static class SingletonHolder{
static final NettyClient instance = new NettyClient();
}
public static NettyClient getInstance(){
return SingletonHolder.instance;
}
private EventLoopGroup group;
private Bootstrap b;
private ChannelFuture cf;
public NettyClient(){
group = new NioEventLoopGroup();//客户端只需一个与server连接的通道
b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)//设置nio通道
.handler(new LoggingHandler(LogLevel.INFO)) //设置日志
// .option(ChannelOption.SO_BROADCAST,true)
// .remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ClientHandler());//设置客户端业务处理模块
ch.pipeline().addLast(new ReadTimeoutHandler(5));//超时时间设置为5s
}
});
}
//连接
public void connect(){
try {
this.cf = b.connect("127.0.0.1",8089).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 NettyClient c = NettyClient.getInstance();
c.connect();
ChannelFuture cf = c.getChannelFuture();
for(int i=0;i<3;i++){
cf.channel().writeAndFlush("在下");
Thread.sleep(4000);//睡眠测试
}
cf.channel().closeFuture().sync();
}
}
客户端业务处理类
package com.java.Olym.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
public class ClientHandler extends SimpleChannelInboundHandler<ByteBuf>{
@Override
protected void channelRead0(ChannelHandlerContext arg0, ByteBuf in) throws Exception {
System.out.println("Client recived :"+in.toString(CharsetUtil.UTF_8));
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rock!",CharsetUtil.UTF_8));//写出刷新数据给服务器端
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
就不测试了