1,Netty原理和使用
Netty是一個高性能 事件驅動的異步的非堵塞的IO(NIO)框架,用於建立TCP等底層的連接,基於Netty可以建立高性能的Http服務器。支持HTTP、 WebSocket 、Protobuf、 Binary TCP |和UDP,Netty已經被很多高性能項目作爲其Socket底層基礎,如HornetQ Infinispan Vert.x
Play Framework Finangle和 Cassandra。其競爭對手是:Apache MINA和 Grizzly。
傳統堵塞的IO讀取如下:
InputStream is = new FileInputStream(“input.bin”);
int byte = is.read(); // 當前線程等待結果到達直至錯誤
而使用NIO如下:
while (true) {
selector.select(); // 從多個通道請求事件
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectorKey key = (SelectionKey) it.next();
handleKey(key);
it.remove();
}
}
堵塞與非堵塞原理
傳統硬件的堵塞如下,從內存中讀取數據,然後寫到磁盤,而CPU一直等到磁盤寫完成,磁盤的寫操作是慢的,這段時間CPU被堵塞不能發揮效率。
使用非堵塞的DMA如下圖:CPU只是發出寫操作這樣的指令,做一些初始化工作,DMA具體執行,從內存中讀取數據,然後寫到磁盤,當完成寫後發出一箇中斷事件給CPU。這段時間CPU是空閒的,可以做別的事情。這個原理稱爲Zero.copy零拷貝。
Netty底層基於上述Java NIO的零拷貝原理實現:
2,Hello world
程序員們習慣的上手第一步,自然是”Hello world”,不過Netty官網的例子卻偏偏拋棄了”Hello world”。那我們就自己寫一個最簡單的”Hello world”的例子,作爲上手。
編寫服務端代碼
/**
* Netty 服務端代碼
*
* @author lichch
*/
public class HelloServer {
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 HelloServerHandler());
}
});
// 開放8000端口供客戶端訪問。
bootstrap.bind(new InetSocketAddress(8000));
}
private static class HelloServerHandler extends
SimpleChannelHandler {
/**
* 當有客戶端綁定到服務端的時候觸發,打印"Hello world, I'm server."
*
* @author lichch
*/
@Override
public void channelConnected(
ChannelHandlerContext ctx,
ChannelStateEvent e) {
System.out.println("Hello world, I'm server.");
}
}
}
**客戶端代碼**
/**
* Netty 客戶端代碼
*
* @author lichch
*/
public class HelloClient {
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 HelloClientHandler());
}
});
// 連接到本地的8000端口的服務端
bootstrap.connect(new InetSocketAddress(
"127.0.0.1", 8000));
}
private static class HelloClientHandler extends SimpleChannelHandler {
/**
* 當綁定到服務端的時候觸發,打印"Hello world, I'm client."
*
* @author lichch
*/
@Override
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent e) {
System.out.println("Hello world, I'm client.");
}
}
}
“`
小結
Netty中,需要區分Server和Client服務。所有的Client都是綁定在Server上的,他們之間是不能通過Netty直接通信的。(自己採用的其他手段,不包括在內。)。白話一下這個通信過程,Server端開放端口,供Client連接,Client發起請求,連接到Server指定的端口,完成綁定。隨後便可自由通信。其實就是普通Socket連接通信的過程。
Netty框架是基於事件機制的,簡單說,就是發生什麼事,就找相關處理方法。就跟着火了找119,搶劫了找110一個道理。所以,這裏,我們處理的是當客戶端和服務端完成連接以後的這個事件。什麼時候完成的連接,Netty知道,他告訴我了,我就負責處理。這就是框架的作用。Netty,提供的事件還有很多,以後會慢慢的接觸和介紹。