参考学习文章:http://ifeve.com/netty5-user-guide/
Server类:
package com.zyh.study.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.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Description:
* @Author: zyh
* @Date: created in 2018/7/22
*/
public class Server {
public static void main(String[] args) throws Exception {
//用于处理服务器端接受客户端连接的线程组
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//用于进行网络通讯(读写)的线程组
NioEventLoopGroup workGroup = new NioEventLoopGroup();
//创建辅助工具类,用于服务器通道的一系列的配置
ServerBootstrap sb = new ServerBootstrap();
sb.group(bossGroup,workGroup)//绑定两个线程组
.channel(NioServerSocketChannel.class)//指定NIO的网络传输模式为TCP,UDP:NioDatagramChannel
.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() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ServerHandler());//这里配置具体数据接收方法的处理
}
});
ChannelFuture cf1 = sb.bind(8787).sync();//异步的绑定指定的端口
ChannelFuture cf2 = sb.bind(8686).sync();//netty可以绑定多个端口
cf1.channel().closeFuture().sync();//等待关闭,相当于Thread.sleep(Integer.MAX_VALUE)
cf2.channel().closeFuture().sync();
//关闭线程组
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
ServerHandler类:(用于处理server接收到的消息)
package com.zyh.study.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;
/**
* @Description:
* @Author: zyh
* @Date: created in 2018/7/22
*/
public class ServerHandler extends ChannelHandlerAdapter{
/**
* 重写读数据时处理的方法
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
//声明字节数组,buf.readableBytes()返回的是buf缓冲中可读的字节数
byte[] req = new byte[buf.readableBytes()];
//将buf缓冲区中的字节读取到字节数组req中
buf.readBytes(req);
String body = new String(req, "utf-8");
System.out.println("Server打印接收到的信息:" + body);
String response = "Server返回给Client的响应信息:" + body;
//1.ctx.writeAndFlush()方法相当于连续调用了write()和flush()方法,因为write()方法只是将buf写到了渠道的缓冲区中,flush()方法会将缓冲区中的数据传给客户端
//2.这里Unpooled工具类的作用就是讲字节数组转成netty的ByteBuf对象
//3.这里使用了writeAndFlush()方法会自动释放buf缓冲区所以不需要想ClientHandler中那样finally中手动释放buf缓冲区了
//4.addListener()方法:当监听到服务器将数据写给客户端,并且确认客户端已经收到信息后,
// 服务器端就会主动去关闭跟客户端的连接,因为客户端调用了cf1.channel().closeFuture().sync()方法,所以客户端这里的阻塞就会打开,继续向后执行代码
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
// .addListener(ChannelFutureListener.CLOSE);
}
/**
* 重写读数据出现异常处理的方法
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
Client类:
package com.zyh.study.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.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @Description:
* @Author: zyh
* @Date: created in 2018/7/22
*/
public class Client {
public static void main(String[] args) throws Exception{
NioEventLoopGroup group = new NioEventLoopGroup();//用于处理网络通信(读写)的线程组
Bootstrap b = new Bootstrap();//创建客户端辅助类工具
b.group(group)//绑定线程组
.channel(NioSocketChannel.class)//设置通信渠道为TCP协议
.handler(new ChannelInitializer() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new ClientHandler());//这里配置具体数据接收方法的处理
}
});
/*与8787端口通讯*/
ChannelFuture cf1 = b.connect("127.0.0.1", 8787).sync();//异步建立连接
cf1.channel().write(Unpooled.copiedBuffer("hello world".getBytes()));//将“hello world”写到buf缓冲区
cf1.channel().flush();//这里必须使用flush(),只用冲刷才能将buf缓冲区中的数据传给服务器端
/*与8686端口通讯*/
ChannelFuture cf2 = b.connect("127.0.0.1", 8686).sync();
cf2.channel().writeAndFlush(Unpooled.copiedBuffer("hello netty".getBytes()));
cf1.channel().closeFuture().sync();//等待关闭,相当于Thread.sleep(Integer.MAX_VALUE)
cf2.channel().closeFuture().sync();
group.shutdownGracefully();//关闭线程组
}
}
ClientHandler类:(用于处理Client端接收到的消息)
package com.zyh.study.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.util.ReferenceCountUtil;
import java.nio.ByteBuffer;
/**
* @Description:
* @Author: zyh
* @Date: created in 2018/7/22
*/
public class ClientHandler extends ChannelHandlerAdapter {
/**
* 重写读数据时处理的方法
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
ByteBuf buf = (ByteBuf) msg;
//声明字节数组,buf.readableBytes()返回的是buf缓冲中可读的字节数
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "utf-8");
System.out.println("Client打印接收到的信息:" + body);
}finally {
ReferenceCountUtil.release(msg);//buf缓冲区使用完了,必须释放
}
}
/**
* 重写读数据出现异常处理的方法
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}