如果我們想要開發client-server應用程式,大部份的programmer會使用較熟悉的http協定來開發web service,以慣用java的programmer來說最常用的http container就是tomcat。但隨著project需求變化,我們會發現這一類的協定或實作有時不易擴展(scale)的很好,我們會想要高度客製化來滿足我們的特殊需求。
這時我們可能會需要Netty,以下是取自Netty官網對於Netty的介紹
The Netty project is an effort to provide an asynchronous event-driven network application framework and tooling for the rapid development of maintainable high-performance · high-scalability protocol servers and clients.
也就是說Netty是一個framework,一個socket框架,並非僅是web server如tomcat,我們可以拿Netty來開發http, ftp, snmp一類的協定, 或者是自定的協定。
以下介紹使用Netty來實作簡單的Echo Server。從名稱可知此範例的server接收到來自clent的訊息後就回應相同的訊息回去給client。 執行時server會listen一個port。client可使用telnet來連此server的port,連上後client便可開始送訊息,server收到後也會回應相同的訊息回去。
首先直接撰寫handler部份,handler負責處理Netty產生的I/O event. 此範例的重點就是將收到的訊息再回傳回去。
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class EchoServerHandler extends ChannelInboundHandlerAdapter {//(1)
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {//(2)
// echo
ctx.write(msg); // (3)
ctx.flush(); // (4)
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
- handler需extend ChannelInboundHandlerAdapter
- override channelRead method,當server收到訊息後此method會被呼叫
- ChannelHandlerContext有提供許多的method來觸發一些io event,在這個範例中使用write來回傳資料至client
- ctx.write()被呼叫時並未立即將資料送至client,僅是先buffer起來,當ctx.flush()被呼叫時才是送到client
主要的處理邏輯寫完了,接下來就是寫main來啟動server並使用EchoServerHandler
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class EchoServer {
private int port;
public EchoServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); // (5)
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to
// gracefully
// shut down your server.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new EchoServer(port).run();
}
}
- NioEventLoopGroup is a multithreaded event loop that handles I/O operation.
- ServerBootstrap 是個helper class用來設定server相關的參數.
- 此範例指定NioServerSocketChannel來處理進來的連線
- 指定channel要使用剛撰寫的的EchoServerHandler
- bind指定的port並啟動server
測試
首先先將server run起來,(直接用java run EchoServer main())。接著開終端機來下指令telnet localhost 8080,等連上後就可以開始送訊息了!畫面如下,其中(1)(3)是向erver送出的訊息,(2)(4)是server回應的訊息
jamestekiMacBook-Pro:~ james$ telnet localhost 8080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
hello (1)
hello (2)
world (3)
world (4)
Summary
在study Netty過程中常會看到Jetty, Tomcat, Mina。這邊做個簡單的比較。Jetty是http容器,和Tomcat是同样的概念,但是具體實現不一樣。 Netty是socket框架,和MINA是相同的概念,但是具體實現不一樣。 據說Mina跟Netty是來自同一個作者,但Mina好像較少在更新了比較沒有Netty來的活躍。
參考來源 http://netty.io/wiki/user-guide-for-4.x.html#wiki-h3-15
沒有留言:
張貼留言