1. 程式人生 > >Java NIO框架Netty教程(三)

Java NIO框架Netty教程(三)

瞭解了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的使用。我們一起學習。