不像 DISCARD 和 ECHO 的服務(wù)端,對(duì)于 TIME 協(xié)議我們需要一個(gè)客戶端,因?yàn)槿藗儾荒馨岩粋€(gè)32位的二進(jìn)制數(shù)據(jù)翻譯成一個(gè)日期或者日歷。在這一部分,我們將會(huì)討論如何確保服務(wù)端是正常工作的,并且學(xué)習(xí)怎樣用Netty 編寫(xiě)一個(gè)客戶端。
在 Netty 中,編寫(xiě)服務(wù)端和客戶端最大的并且唯一不同的使用了不同的BootStrap 和 Channel的實(shí)現(xiàn)。請(qǐng)看一下下面的代碼:
public class TimeClient {
public static void main(String[] args) throws Exception {
String host = args[0];
int port = Integer.parseInt(args[1]);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap(); // (1)
b.group(workerGroup); // (2)
b.channel(NioSocketChannel.class); // (3)
b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
});
// 啟動(dòng)客戶端
ChannelFuture f = b.connect(host, port).sync(); // (5)
// 等待連接關(guān)閉
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
}
1.BootStrap 和 ServerBootstrap 類似,不過(guò)他是對(duì)非服務(wù)端的 channel 而言,比如客戶端或者無(wú)連接傳輸模式的 channel。
2.如果你只指定了一個(gè) EventLoopGroup,那他就會(huì)即作為一個(gè) boss group ,也會(huì)作為一個(gè) workder group,盡管客戶端不需要使用到 boss worker 。
3.代替NioServerSocketChannel的是NioSocketChannel,這個(gè)類在客戶端channel 被創(chuàng)建時(shí)使用。
4.不像在使用 ServerBootstrap 時(shí)需要用 childOption() 方法,因?yàn)榭蛻舳说?SocketChannel 沒(méi)有父親。
5.我們用 connect() 方法代替了 bind() 方法。
正如你看到的,他和服務(wù)端的代碼是不一樣的。ChannelHandler 是如何實(shí)現(xiàn)的?他應(yīng)該從服務(wù)端接受一個(gè)32位的整數(shù)消息,把他翻譯成人們能讀懂的格式,并打印翻譯好的時(shí)間,最后關(guān)閉連接:
import java.util.Date;
public class TimeClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf m = (ByteBuf) msg; // (1)
try {
long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L;
System.out.println(new Date(currentTimeMillis));
ctx.close();
} finally {
m.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
1.在TCP/IP中,Netty 會(huì)把讀到的數(shù)據(jù)放到 ByteBuf 的數(shù)據(jù)結(jié)構(gòu)中。
這樣看起來(lái)非常簡(jiǎn)單,并且和服務(wù)端的那個(gè)例子的代碼也相差不多。然而,處理器有時(shí)候會(huì)因?yàn)閽伋?IndexOutOfBoundsException 而拒絕工作。在下個(gè)部分我們會(huì)討論為什么會(huì)發(fā)生這種情況。
更多建議: