向客户端回写数据
目标
上一章节我们初步了解了Netty实现一个服务端程序,并本章节我们要了解如何读取客户端发送过来的数据,并且向客户端发送数据
实现一个echo服务
echo服务就是收到什么数据就直接打印出来
同样的我们需要创建一个handler来处理客户端发送的数据,然后把这个handler添加到pipeline中。
package io.netty.example.echo;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerAdapter;
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
try {
while (in.isReadable()) {
System.out.print((char) in.readByte());
System.out.flush();
}
} finally {
ReferenceCountUtil.release(msg);
}
}
}
收到的数据是ByteBuf格式,读取缓冲区中所有可读的字节,并转换为char类型打印出来。最后重要的是要记得要显示的释放资源。
如果每次要手动写释放资源的代码很麻烦(况且还容易粗心漏掉)那么可以修改代码将继承的ChannelHandlerAdapter修改为 SimpleChannelInboundHandler。我们只需要重写channelRead0 抽象,channelRead方法内部会调用channelRead0并在执行完成后帮助我们释放掉缓冲区
实现一个时间服务器
当客户端连接上服务端时,服务端立即向客户端返回服务器当时时间信息
package io.netty.example.time;
public class TimeServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(final ChannelHandlerContext ctx) {
final ByteBuf time = ctx.alloc().buffer(4);
time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
final ChannelFuture f = ctx.writeAndFlush(time);
f.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
assert f == future;
ctx.close();
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
- 当客户端连接到服务器后,会触发handler中的 channelActive方法,通过参数ChannelHandlerContext 我们即可操作通道写数据。
- 向通道中写数据也是需要通过缓冲区的,那么我们就要创建一个缓冲区存放我们要写给客户端的数据,ctx.alloc().buffer(4) 动态申请4字节内存。通过ctx.writeAndFlush把缓冲区数据写入通道,并flush出去。如果只调用write方法,客户端并不会马上收到数据。
- 写完数据后我们需要关闭连接,那么我们就需要知道数据是否已经写入完成,因此上面代码中需要添加listener,并在完成后通过ctx.close关闭通道。
到此我们已经初步了解到了如何用Netty实现服务端并读写数据,下章我们要学习如何编写客户端的程序
浙公网安备 33010602011771号