注:源代码来自享学课堂,学习之后所做笔记,方便回顾,也给大家一个参考
1、Client主函数
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
public class EchoClient {
private final int port;
private final String host;
public EchoClient(int port, String host) {
this.port = port;
this.host = host;
}
//netty的标准程序基本都是下面这个流程
public void start() throws InterruptedException {
/*线程组*/
EventLoopGroup group = new NioEventLoopGroup();
try {
/*客户端启动必备,服务端使用ServerBootstrap*/
Bootstrap b = new Bootstrap();
b.group(group)
/*指明使用NIO进行网络通讯*/
.channel(NioSocketChannel.class)
/*配置远程服务器的地址,服务器端就是配置LocalAdderss*/
.remoteAddress(new InetSocketAddress(host,port))
//这里配置我们自定义的handler,netty主要就是写各种各样的handler
.handler(new EchoClientHandler());
/*连接到远程节点,阻塞等待直到连接完成*/
ChannelFuture f = b.connect().sync();
/*阻塞,直到channel关闭*/
f.channel().closeFuture().sync();
} finally {
//阻塞关闭线程组
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws InterruptedException {
new EchoClient(8080,"127.0.0.1").start();
}
}
2、自定义客户端Handler
在channelActive建立连接之后,循环100次数据,本来应该是server接受100次的,但是看最后的结果只接受了两次
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;
//SimpleChannelInboundHandler帮我们封装好了很多东西,客户端和服务端都是使用ByteBuf通信的
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
/*客户端读取到服务器发送过来的数据了,在这里做处理*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
throws Exception {
System.out.println("Client accept:" + msg.toString(CharsetUtil.UTF_8));
}
/*客户端被通知channel活跃以后,做事*/
//这里循环发送数据
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 0; i < 100; i++) {
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello,Netty ",
CharsetUtil.UTF_8));
}
}
//客户端读取数据完毕之后做事
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelReadComplete");
}
//发生异常的处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
4、Server端主函数
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 java.net.InetSocketAddress;
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws InterruptedException {
int port = 8080;
EchoServer echoServer = new EchoServer(port);
System.out.println("服务器即将启动");
echoServer.start();
System.out.println("服务器关闭");
}
//代码大致和客户端相同,不同1\ServerBootstrap,2\childHandler
public void start() throws InterruptedException {
/*线程组*/
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();/*服务端启动必备*/
b.group(group)
/*指明使用NIO进行网络通讯*/
.channel(NioServerSocketChannel.class)
//.channel(EpollServerSocketChannel.class)
/*指明服务器监听端口*/
.localAddress(new InetSocketAddress(port))
/*接收到连接请求,新启一个socket通信,也就是channel,每个channel
* 有自己的事件的handler*/
.childOption(ChannelOption.TCP_NODELAY,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoServerHandler());
}
});
ChannelFuture f = b.bind().sync();/*绑定到端口,阻塞等待直到连接完成*/
/*阻塞,直到channel关闭*/
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
5、server端的Handler
counter.incrementAndGet()用来计算客户端发送数据的次数,客户端循环了100次,但是服务端只接受了
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import java.util.concurrent.atomic.AtomicInteger;
/*指明我这个handler可以在多个channel之间共享,意味这个实现必须线程安全的。*/
@ChannelHandler.Sharable//如果不加这个注解,主函数在.childHandler(new EchoServerHandler()),确保每个链接都单独的handler
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
private AtomicInteger counter = new AtomicInteger();
/*** 服务端读取到网络数据后的处理*/
//计算接受数据次数,按道理客户端发送了100次,也应该接受100次,结果只有两次
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
ByteBuf in = (ByteBuf) msg;/*netty实现的缓冲区*/
System.out.println("Server Accept:" + in.toString(CharsetUtil.UTF_8) + counter.incrementAndGet());
ctx.write(in);
}
/*** 服务端读取完成网络数据后的处理*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx)
throws Exception {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)/*flush掉所有的数据*/
.addListener(ChannelFutureListener.CLOSE);/*当flush完成后,关闭连接*/
}
/*** 发生异常后的处理*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
6、运行结果
server
服务器即将启动
Server Accept:Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hell1
Server Accept:o,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty Hello,Netty 2
这里只发生了两次,即粘包
client
Client accetp:Hello,Netty
channelReadComplete
channelReadComplete
Process finished with exit code 0
下一篇介绍netty解决粘包半包的三种基本方法