Java NIO框架Netty教程(三)
阿新 • • 發佈:2018-12-23
瞭解了Netty的基本概念,開發起來應該會順手很多。在“Hello World”程式碼中,我們只是在完成繫結的時候,在各自的本地列印了簡單的資訊,並沒有客戶端和服務端的訊息傳遞。這個肯定是最基本的功能。在上程式碼之前,先補充一個Netty中重要的概念,ChannelBuffer。
ChannelBuffer
Netty中的訊息傳遞,都必須以位元組的形式,以ChannelBuffer為載體傳遞。簡單的說,就是你想直接寫個字串過去,對不起,拋異常。雖然,Netty定義的writer的介面引數是Object的,這可能也是會給新上手的朋友容易造成誤會的地方。Netty原始碼中,是這樣判斷的:
SendBuffer acquire(Object message) {
if (message instanceof ChannelBuffer) {
return acquire((ChannelBuffer) message);
} else if (message instanceof FileRegion) {
return acquire((FileRegion) message);
}
throw new IllegalArgumentException(
"unsupported message type: " + message.getClass());
}
所以,我們要想傳遞字串,那麼就必須轉換成ChannelBuffer。明確了這一點,接下來我們上程式碼:
/**
* @author lihzh
* @alia OneCoder
* @blog http://www.coderli.com
*/
public class MessageServer {
public static void main(String args[]) {
// Server服務啟動器
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// 設定一個處理客戶端訊息和各種訊息事件的類(Handler)
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new MessageServerHandler());
}
});
// 開放8000埠供客戶端訪問。
bootstrap.bind(new InetSocketAddress(8000));
}
private static class MessageServerHandler extends SimpleChannelHandler {
/**
* 使用者接受客戶端發來的訊息,在有客戶端訊息到達時觸發
*
* @author lihzh
* @alia OneCoder
*/
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
System.out.println(buffer.toString(Charset.defaultCharset()));
}
}
}
/**
* @author lihzh
* @alia OneCoder
* @blog http://www.coderli.com
*/
public class MessageClient {
public static void main(String args[]) {
// Client服務啟動器
ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// 設定一個處理服務端訊息和各種訊息事件的類(Handler)
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new MessageClientHandler());
}
});
// 連線到本地的8000埠的服務端
bootstrap.connect(new InetSocketAddress("127.0.0.1", 8000));
}
private static class MessageClientHandler extends SimpleChannelHandler {
/**
* 當繫結到服務端的時候觸發,給服務端發訊息。
*
* @alia OneCoder
* @author lihzh
*/
@Override
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent e) {
// 將字串,構造成ChannelBuffer,傳遞給服務端
String msg = "Hello, I'm client.";
ChannelBuffer buffer = ChannelBuffers.buffer(msg.length());
buffer.writeBytes(msg.getBytes());
e.getChannel().write(buffer);
}
}
}
與“Hello World”樣例程式碼不同的是,客戶端在channel連通後,不是在本地列印,而是將訊息轉換成ChannelBuffer傳遞給服務端,服務端接受到ChannelBuffer後,解碼成字串打印出來。同時,通過對比可以發現,變動的只是Handler裡的程式碼,啟動服務和繫結服務的程式碼沒有變化,也就是我們在概念介紹裡提到了,關注Handler,在Handler裡處理我們自己的業務。所以,以後我們會只給出業務中關鍵程式碼,不會在上重複的程式碼:)
由於在Netty中訊息的收發全依賴於ChannelBuffer,所以,下一章我們將會詳細的介紹ChannelBuffer的使用。我們一起學習。