W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
出于網(wǎng)絡(luò)的原因,有一個(gè)特殊的問題需要我們思考,就是如何能夠有效的在異步框架寫大數(shù)據(jù)。因?yàn)閷懖僮魇欠亲枞?,即使不能寫出?shù)據(jù),也只是通知 ChannelFuture 完成了。每當(dāng)發(fā)生這種情況,就必須停止寫操作或面臨內(nèi)存耗盡的風(fēng)險(xiǎn)。所以在進(jìn)行寫操作的時(shí)候,會(huì)產(chǎn)生的大量的數(shù)據(jù),在這種情況下我們要準(zhǔn)備好處理因?yàn)檫B接遠(yuǎn)端緩慢而導(dǎo)致的延遲釋放內(nèi)存的問題。作為一個(gè)例子讓我們考慮寫一個(gè)文件的內(nèi)容到網(wǎng)絡(luò)。
我們討論傳輸?shù)臅r(shí)候,有提到 NIO 的“zero-copy(零拷貝)”功能,消除移動(dòng)一個(gè)文件的內(nèi)容從文件系統(tǒng)到網(wǎng)絡(luò)堆棧的復(fù)制步驟。所有這一切發(fā)生在 Netty 的核心,因此所有所需的應(yīng)用程序代碼是使用 interface FileRegion 的實(shí)現(xiàn),在 Netty 的API 文檔中定義如下為一個(gè)通過 Channel 支持 zero-copy 文件傳輸?shù)奈募^(qū)域。
下面演示了通過 zero-copy 將文件內(nèi)容從 FileInputStream 創(chuàng)建 DefaultFileRegion 并寫入 使用 Channel
Listing 8.11 Transferring file contents with FileRegion
FileInputStream in = new FileInputStream(file); //1
FileRegion region = new DefaultFileRegion(in.getChannel(), 0, file.length()); //2
channel.writeAndFlush(region).addListener(new ChannelFutureListener() { //3
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.cause(); //4
// Do something
}
}
});
只是看到的例子只適用于直接傳輸一個(gè)文件的內(nèi)容,沒有執(zhí)行的數(shù)據(jù)應(yīng)用程序的處理。在相反的情況下,將數(shù)據(jù)從文件系統(tǒng)復(fù)制到用戶內(nèi)存是必需的,您可以使用 ChunkedWriteHandler。這個(gè)類提供了支持異步寫大數(shù)據(jù)流不引起高內(nèi)存消耗。
這個(gè)關(guān)鍵是 interface ChunkedInput,實(shí)現(xiàn)如下:
名稱 | 描述 |
---|---|
ChunkedFile | 當(dāng)你使用平臺(tái)不支持 zero-copy 或者你需要轉(zhuǎn)換數(shù)據(jù),從文件中一塊一塊的獲取數(shù)據(jù) |
ChunkedNioFile | 與 ChunkedFile 類似,處理使用了NIOFileChannel |
ChunkedStream | 從 InputStream 中一塊一塊的轉(zhuǎn)移內(nèi)容 |
ChunkedNioStream | 從 ReadableByteChannel 中一塊一塊的轉(zhuǎn)移內(nèi)容 |
清單 8.12 演示了使用 ChunkedStream,實(shí)現(xiàn)在實(shí)踐中最常用。 所示的類被實(shí)例化一個(gè) File 和一個(gè) SslContext。當(dāng) initChannel() 被調(diào)用來初始化顯示的處理程序鏈的通道。
當(dāng)通道激活時(shí),WriteStreamHandler 從文件一塊一塊的寫入數(shù)據(jù)作為ChunkedStream。最后將數(shù)據(jù)通過 SslHandler 加密后傳播。
Listing 8.12 Transfer file content with FileRegion
public class ChunkedWriteHandlerInitializer extends ChannelInitializer<Channel> {
private final File file;
private final SslContext sslCtx;
public ChunkedWriteHandlerInitializer(File file, SslContext sslCtx) {
this.file = file;
this.sslCtx = sslCtx;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new SslHandler(sslCtx.createEngine()); //1
pipeline.addLast(new ChunkedWriteHandler());//2
pipeline.addLast(new WriteStreamHandler());//3
}
public final class WriteStreamHandler extends ChannelInboundHandlerAdapter { //4
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
ctx.writeAndFlush(new ChunkedStream(new FileInputStream(file)));
}
}
}
ChunkedInput 所有被要求使用自己的 ChunkedInput 實(shí)現(xiàn),是安裝ChunkedWriteHandler 在管道中
在本節(jié)中,我們討論
在下一節(jié)中我們將研究幾種不同方法來序列化 POJO。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: