本博客 貓叔的博客,轉載請申明出處閱讀本文約 “4分鐘”
適讀人羣:Java-Netty 初級
無限異步發送數據流
版本:netty 4.1.*申明:本文旨在重新分享討論Netty官方相關案例,添加部分個人理解與要點解析。
這個是InChat的案例地址,裏面補充了詳細的註釋,比起官方會容易看一點。
官方案例地址:https://netty.io/4.1/xref/io/...
正文
- DiscardClient(客戶端)
- DiscardClientHandler
- DiscardServer(服務端)
- DiscardServerHandler
要點介紹
- ChannelInboundHandlerAdapter 官方介紹
實現了抽象基類ChannelInboundHandler,因此也提供其所有方法的實現,子類可以重寫方法實現來改變它。
注意:channelRead(ChannelHandlerContext, Object) 方法自動返回後不會釋放消息。如果您正在尋找ChannelInboundHandler自動發佈收到的消息的實現,請參閱SimpleChannelInboundHandler
- SimpleChannelInboundHandler 官方介紹
允許顯式只處理特定類型的消息
- writeZero(int length) 官方介紹
從當前開始 用(0x00)填充此緩衝區writerIndex並按writerIndex指定值增加length。如果this.writableBytes小於length,ensureWritable(int) 將調用以嘗試擴展容量以適應。
- directBuffer(int initialCapacity) 官方介紹
使用給定的初始值給ByteBuf分配直接值
- release() 官方介紹
每一個新分配的ByteBuf的引用計數值爲1,每對這個ByteBuf對象增加一個引用,需要調用ByteBuf.retain()方法,而每減少一個引用,需要調用ByteBuf.release()方法。當這個ByteBuf對象的引用計數值爲0時,表示此對象可回收
- retainedDuplicate() 官方介紹
返回保留的緩衝區,該緩衝區共享此緩衝區的整個區域。修改返回的緩衝區或此緩衝區的內容會影響彼此的內容,同時它們會維護單獨的索引和標記。此方法的行爲類似於此方法,duplicate().retain()但此方法可能返回產生較少垃圾的緩衝區實現。
- ChannelFutureListener 官方介紹
監聽一個ChannelFuture的結果。Channel一旦通過調用添加此偵聽器,將以ChannelFuture.addListener(GenericFutureListener)異步I / O的操作通知結果。
項目源碼
- DiscardClient(客戶端)
/**
* @ClassName DiscardClient
* @Description TODO
* @Author MySelf
* @Date 2019/8/19 20:38
* @Version 1.0
**/
public final class DiscardClient {
//判斷是否加密
static final boolean SSL = System.getProperty("ssl") != null;
//監聽本地服務
static final String HOST = System.getProperty("host", "127.0.0.1");
//監聽端口
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
//發送消息的大小,用於EchoClientHandler
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public static void main(String[] args) throws Exception {
//公共抽象類,安全套接字協議實現充當工廠SSLEngine和SslHandler。在內部,它通過JDK SSLContext或OpenSSL 實現SSL_CTX
final SslContext sslCtx;
if (SSL){
//用於配置新SslContext以進行創建的構建器
sslCtx = SslContextBuilder.forClient()
//用於驗證遠程端點證書的可信管理器
//InsecureTrustManagerFactory:在TrustManagerFactory沒有任何驗證的情況下信任所有X.509證書的不安全因素
//注:切勿TrustManagerFactory在生產中使用它。它純粹是出於測試目的,因此非常不安全。
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
}else {
sslCtx = null;
}
//事件循環
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline p = sc.pipeline();
//瞭解SslContext的用法
if (sslCtx != null){
p.addLast(sslCtx.newHandler(sc.alloc(),HOST,PORT));
}
p.addLast(new DiscardClientHandler());
}
});
ChannelFuture f = b.connect(HOST,PORT).sync();
f.channel().closeFuture().sync();
}finally {
group.shutdownGracefully();
}
}
}
- DiscardClientHandler
/**
* @ClassName DiscardClientHandler
* @Description TODO
* @Author MySelf
* @Date 2019/8/19 20:38
* @Version 1.0
**/
public class DiscardClientHandler extends SimpleChannelInboundHandler<Object> {
private ByteBuf content;
private ChannelHandlerContext ctx;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
// 初始化消息
content = ctx.alloc().directBuffer(DiscardClient.SIZE).writeZero(DiscardClient.SIZE);
// 發送初始信息
generateTraffic();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//引用計數爲0,釋放
content.release();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 引發異常時關閉連接
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
// 服務器應該不發送任何內容,但如果它發送什麼,丟棄它。
}
// 生成數據
private void generateTraffic(){
// 將出站緩衝區刷新到套接字
// 刷新後,再次生成相同數量的流量
ctx.writeAndFlush(content.retainedDuplicate()).addListener(trafficGenerator);
}
// 數據觸發
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
//完成操作後的方法調用,即只要成功無限調用generateTraffic()
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (channelFuture.isSuccess()){
generateTraffic();
}else {
channelFuture.cause().printStackTrace();
channelFuture.channel().close();
}
}
};
}
- DiscardServer(服務端)
/**
* @ClassName DiscardServer
* @Description TODO
* @Author MySelf
* @Date 2019/8/19 20:38
* @Version 1.0
**/
public class DiscardServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
public static void main(String[] args) throws Exception {
final SslContext sslCtx;
if (SSL){
//SelfSignedCertificate:生成臨時自簽名證書以進行測試
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
}else{
sslCtx = null;
}
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null){
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new DiscardServerHandler());
}
});
// 綁定並開始接受傳入連接
ChannelFuture f = b.bind(PORT).sync();
// 等待服務器套接字關閉
// 這個例子,這不會發生,但你可以這樣優雅的做
f.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
- DiscardServerHandler
/**
* @ClassName DiscardServerHandler
* @Description TODO
* @Author MySelf
* @Date 2019/8/19 20:39
* @Version 1.0
**/
public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
// discard
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 引發異常時關閉連接
cause.printStackTrace();
ctx.close();
}
}
公衆號:Java貓說
學習交流羣:728698035
現架構設計(碼農)兼創業技術顧問,不羈平庸,熱愛開源,雜談程序人生與不定期乾貨。