繼續翻譯:http://netty.io/wiki/user-guide-for-5.x.htmlhtml
最簡單的協議不是hello,而是DISCARD. bootstrap
也就是說,忽略全部收到的數據,不返回任何響應。api
爲了完成這個協議,你僅僅須要作的是忽略全部收到的數據,讓咱們開始從handler實現開始,這個處理IO事件(來源於Netty).服務器
package io.netty.example.discard;網絡
import io.netty.buffer.ByteBuf;多線程
import io.netty.channel.ChannelHandlerContext;app
import io.netty.channel.ChannelHandlerAdapter;socket
/**tcp
* Handles a server-side channel.ide
*/
public class DiscardServerHandler extends ChannelHandlerAdapter { // (1)
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
// Discard the received data silently.
((ByteBuf) msg).release(); // (3)
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
DiscardServerHandler extends ChannelHandlerAdapter, 是對ChannelHandler的一個實現. ChannelHandler 提供了各類各樣的事件方法可覆蓋.
目前,繼承 ChannelHandlerAdapter足夠了 而不是本身實現接口裏的方法。
咱們重寫了channelRead() 事件方法,這個方法被接收到的消息調用,當從客戶端裏接收到新數據時。在這個例子當中,接收到的信息是 ByteBuf.
爲了實現DISCARD協議,方法必須忽略收到的消息,ByteBuf 是一個計數器方式引用的對象,只有顯式的經過release()方法才能夠釋放這個對象。請注意:這個handler有責任來釋聽任何傳給本身的計數器引用的對象。
一般, channelRead() 方法用如下形式實現
@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { try { // Do something with msg } finally { ReferenceCountUtil.release(msg); }}
The exceptionCaught() 事件方法:
當處理事件時,IO錯誤或者handler實現裏有異常拋出。
大多數狀況下,異常應該記錄下來,而且相關的channel應該被關閉,儘管這個方法的實現能夠不一樣,這依賴於你想怎麼處理。
好比,你也許想發送一個響應消息伴隨錯誤碼在關閉鏈接以前。
咱們已經實現了一半,剩下的是寫main()方法來啓動這個服務器。
package io.netty.example.discard;
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;
/**
* Discards any incoming data.
*/
public class DiscardServer {
private int port;
public DiscardServer(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 DiscardServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); // (7)
// 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 DiscardServer(port).run();
}
}
1. NioEventLoopGroup 是一個多線程的事件循環,處理IO操做。
Netty提供了各類各樣的 EventLoopGroup實現來應對不一樣種類的傳輸。
咱們在例子中實現服務器端的工程,所以兩個NioEventLoopGroup 將會被使用,第一個,常常叫作boss,接收一個進來的鏈接,第二個,叫作worker,處理流量(接受的鏈接)一旦 boss接收了鏈接而且註冊接收的鏈接到worker.多少線程被使用而且它們如何映射到建立的Channels依賴於 EventLoopGroup 實現,也能夠經過構造器配置。
2. ServerBootstrap 是一個幫助類來安裝服務器,你能夠經過Channel來直接安裝。
3. 儘管如此,要知道,這是一個單調的過程,大多數狀況下不須要作這個。
4. 這裏,咱們使用了 NioServerSocketChannel 類來初始化一個新的Channel來接收進來的鏈接。這個handler老是被新接受的channel調用。
5. ChannelInitializer是一個特別的handler,目的是幫助一個用戶來配置一個新的Channel. 最有可能的就是你想配置 ChannelPipeline of the new Channel 經過增長新的句柄方法好比DiscardServerHandler 來實現你的網絡工程。
6. 一旦工程變複雜了,你將增長更多的方法到pipeline上來,提取這個匿名類到一個底層類裏。
7. 你也能夠設置參數(特定於channel實現),咱們在寫一個TCP/IP服務器,因此咱們能夠設置socket的參數好比tcpNoDelay and keepAlive.
8. 請參考ChannelOption 和特定的ChannelConfig實現來獲取支持的選項說明。
9. 你意識到option()和childOption()?
10. option()是爲了NioServerSocketChannel ,這個接受鏈接。childOption()是爲了channels(被父ServerChannel接受) ,在例子當中是 NioServerSocketChannel 。
11. 咱們準備好了,剩下的就是綁定端口和啓動服務器,這裏,咱們綁定到8080端口,你能夠調用bind()方法任意屢次只要願意。(能夠以不一樣的綁定定製).
祝賀,你已經完成了第一個服務器的開發。
翻譯 | ok | ok | ok |
理解 | ok | ok | ok |