- 浏览: 981550 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
netty 通道接口定义:http://donald-draper.iteye.com/blog/2392740
netty 抽象通道初始化:http://donald-draper.iteye.com/blog/2392801
netty 抽象Unsafe定义:http://donald-draper.iteye.com/blog/2393053
netty 通道Outbound缓冲区:http://donald-draper.iteye.com/blog/2393098
netty 抽象通道后续:http://donald-draper.iteye.com/blog/2393166
netty 抽象nio通道:http://donald-draper.iteye.com/blog/2393269
引言
前一篇文章,我们看了抽象nio通道,先来回顾一下:
抽象nio通道AbstractNioChannel内部关联一个可选择通道(SelectableChannel)和一个选择key(selectionKey)。抽象Nio通道构造,主要是初始化通道并配置为非阻塞模式。
注册doRegister工作主要是,注册可选择通道到通道所在事件循环的选择器中。反注册doDeregister,委托给事件循环,取消选择key,即从事件循环关联选择器的选择key集合中移除当前选择key。开始读操作doBeginRead,实际工作为将读操作事件,添加选择key的兴趣事件集
抽象nioUnsafe为特殊的Unsafe,允许访问底层的选择通道。选择通道方法返回的实际为抽象nio通道内部的底层可选择通道。移除读兴趣事件removeReadOp,即从选择key兴趣事件集中,移除读操作事件。连接操作,将实际连接操作委托给doConnect,待子类实现,如果连接成功,则通知异步任务连接成功,如果是第一次连接,则触发通道的激活事件fireChannelActive。完成连接操作,实际工作委托给抽象Nio通道的doFinishConnect方法,待子类实现,完成后更新任务结果,触发通道的激活事件fireChannelActive,如果出现异常,则更新连接任务为异常失败。
今天我们来看一下抽象nio字节通道AbstractNioByteChannel
来看实际写操作:
从上面可以看出,写通道Outbound缓冲区,即遍历刷新链上的写请求,如果写请求消息为
字节buf,则调用doWriteBytes完成实际数据发送操作,待子类扩展,如果写请求消息为文件Region,调用doWriteFileRegion完成实际数据发送操作,待子类扩展,数据发送,则更新通道的数据发送进度,并从刷新链上移除写请求;如果所有写请求发送完毕,则重新添加写操作事件到选择key兴趣事件集,否则继续刷新通道Outbound缓冲区中的写请求。
//过滤消息
再看其他方法:
从newUnsafe方法,返回的为NioByteUnsafe
我们来看nio字节Unsafe:
从上面可以看出,nio字节Unsafe读操作,从通道接收缓冲区读取数据,
通知通道处理读取数据,触发Channel管道线的fireChannelRead事件,待数据读取完毕,
触发Channel管道线的fireChannelReadComplete事件,如果在读数据的过程中,通道关闭,则
触发通道输入关闭事件(fireUserEventTriggered),如果在读数据的过程中,发生异常,则
读取缓存区中没有读完的数据,并通道通道处理剩余数据。
总结:
写通道Outbound缓冲区,即遍历刷新链上的写请求,如果写请求消息为字节buf,则调用doWriteBytes完成实际数据发送操作,待子类扩展,如果写请求消息为文件Region,调用doWriteFileRegion完成实际数据发送操作,待子类扩展,数据发送,则更新通道的数据发送进度,并从刷新链上移除写请求;如果所有写请求发送完毕,则重新添加写操作事件到选择key兴趣事件集,否则继续刷新通道Outbound缓冲区中的写请求。
nio字节Unsafe读操作,从通道接收缓冲区读取数据,通知通道处理读取数据,触发Channel管道线的fireChannelRead事件,待数据读取完毕,触发Channel管道线的fireChannelReadComplete事件,如果在读数据的过程中,通道关闭,则触发通道输入关闭事件(fireUserEventTriggered),如果在读数据的过程中,发生异常,则读取缓存区中没有读完的数据,并通道通道处理剩余数据。
附:
//ChannelMetadata
//ChannelInputShutdownReadComplete
//ChannelInputShutdownEvent
netty 抽象通道初始化:http://donald-draper.iteye.com/blog/2392801
netty 抽象Unsafe定义:http://donald-draper.iteye.com/blog/2393053
netty 通道Outbound缓冲区:http://donald-draper.iteye.com/blog/2393098
netty 抽象通道后续:http://donald-draper.iteye.com/blog/2393166
netty 抽象nio通道:http://donald-draper.iteye.com/blog/2393269
引言
前一篇文章,我们看了抽象nio通道,先来回顾一下:
抽象nio通道AbstractNioChannel内部关联一个可选择通道(SelectableChannel)和一个选择key(selectionKey)。抽象Nio通道构造,主要是初始化通道并配置为非阻塞模式。
注册doRegister工作主要是,注册可选择通道到通道所在事件循环的选择器中。反注册doDeregister,委托给事件循环,取消选择key,即从事件循环关联选择器的选择key集合中移除当前选择key。开始读操作doBeginRead,实际工作为将读操作事件,添加选择key的兴趣事件集
抽象nioUnsafe为特殊的Unsafe,允许访问底层的选择通道。选择通道方法返回的实际为抽象nio通道内部的底层可选择通道。移除读兴趣事件removeReadOp,即从选择key兴趣事件集中,移除读操作事件。连接操作,将实际连接操作委托给doConnect,待子类实现,如果连接成功,则通知异步任务连接成功,如果是第一次连接,则触发通道的激活事件fireChannelActive。完成连接操作,实际工作委托给抽象Nio通道的doFinishConnect方法,待子类实现,完成后更新任务结果,触发通道的激活事件fireChannelActive,如果出现异常,则更新连接任务为异常失败。
今天我们来看一下抽象nio字节通道AbstractNioByteChannel
package io.netty.channel.nio; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.ChannelPipeline; import io.netty.channel.FileRegion; import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.socket.ChannelInputShutdownEvent; import io.netty.channel.socket.ChannelInputShutdownReadComplete; import io.netty.util.internal.StringUtil; import java.io.IOException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; /** * {@link AbstractNioChannel} base class for {@link Channel}s that operate on bytes. */ public abstract class AbstractNioByteChannel extends AbstractNioChannel { private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);//通道元数据 private static final String EXPECTED_TYPES = " (expected: " + StringUtil.simpleClassName(ByteBuf.class) + ", " + StringUtil.simpleClassName(FileRegion.class) + ')'; private Runnable flushTask;//刷新任务 /** * Create a new instance *创建nio字节通道 * @param parent the parent {@link Channel} by which this instance was created. May be {@code null} * @param ch the underlying {@link SelectableChannel} on which it operates */ protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { //读操作事件为SelectionKey.OP_READ super(parent, ch, SelectionKey.OP_READ); } }
来看实际写操作:
@Override protected void doWrite(ChannelOutboundBuffer in) throws Exception { int writeSpinCount = -1;//写操作自旋此数计数器 boolean setOpWrite = false; for (;;) { //获取当前通道Outbound缓冲区中的当前待刷新消息 Object msg = in.current(); if (msg == null) { // Wrote all messages. //清除通道选择key兴趣事件集中写操作事件 clearOpWrite(); // Directly return here so incompleteWrite(...) is not called. return; } if (msg instanceof ByteBuf) {//如果为字节buf ByteBuf buf = (ByteBuf) msg; int readableBytes = buf.readableBytes(); if (readableBytes == 0) { //可读字节数为0,则从通道Outbound缓存区中移除写请求 in.remove(); continue; } boolean done = false; long flushedAmount = 0; if (writeSpinCount == -1) { //获取通道配置的写请求自旋次数 writeSpinCount = config().getWriteSpinCount(); } for (int i = writeSpinCount - 1; i >= 0; i --) { //实际发送字节数据 int localFlushedAmount = doWriteBytes(buf); if (localFlushedAmount == 0) { //没有字节要发送 setOpWrite = true; break; } //更新刷新字节计数器 flushedAmount += localFlushedAmount; if (!buf.isReadable()) { //如果buf不可读,则数据发送完毕 done = true; break; } } //报告字节数据发送进度 in.progress(flushedAmount); if (done) { //发送完,则移除写请求 in.remove(); } else { // Break the loop and so incompleteWrite(...) is called. break; } } else if (msg instanceof FileRegion) { //如果是文件Region消息 FileRegion region = (FileRegion) msg; boolean done = region.transferred() >= region.count(); if (!done) { long flushedAmount = 0; if (writeSpinCount == -1) { writeSpinCount = config().getWriteSpinCount(); } for (int i = writeSpinCount - 1; i >= 0; i--) { //完成实际写操作 long localFlushedAmount = doWriteFileRegion(region); if (localFlushedAmount == 0) { setOpWrite = true; break; } //更新刷新字节计数器 flushedAmount += localFlushedAmount; if (region.transferred() >= region.count()) { done = true; break; } } //更新数据发送进度 in.progress(flushedAmount); } if (done) { //发送完,则移除写请求 in.remove(); } else { // Break the loop and so incompleteWrite(...) is called. break; } } else { // Should not reach here. throw new Error(); } } //完成写后继任务 incompleteWrite(setOpWrite); }
/** * Write a {@link FileRegion} *写一个文件region,待子类扩展 * @param region the {@link FileRegion} from which the bytes should be written * @return amount the amount of written bytes */ protected abstract long doWriteFileRegion(FileRegion region) throws Exception; /** * Write bytes form the given {@link ByteBuf} to the underlying {@link java.nio.channels.Channel}. 写一个字节buf,待子类扩展 * @param buf the {@link ByteBuf} from which the bytes should be written * @return amount the amount of written bytes */ protected abstract int doWriteBytes(ByteBuf buf) throws Exception;
//完成写后继任务 protected final void incompleteWrite(boolean setOpWrite) { // Did not write completely. if (setOpWrite) { //发送数据完成,则重新添加写操作事件到选择key兴趣事件集 setOpWrite(); } else { //否则,继续刷新通道Outbound缓冲区中的写请求 // Schedule flush again later so other tasks can be picked up in the meantime Runnable flushTask = this.flushTask; if (flushTask == null) { flushTask = this.flushTask = new Runnable() { @Override public void run() { flush(); } }; } eventLoop().execute(flushTask); } } //添加写操作事件到选择key兴趣事件集 protected final void setOpWrite() { final SelectionKey key = selectionKey(); // Check first if the key is still valid as it may be canceled as part of the deregistration // from the EventLoop // See https://github.com/netty/netty/issues/2104 if (!key.isValid()) { return; } final int interestOps = key.interestOps(); if ((interestOps & SelectionKey.OP_WRITE) == 0) { key.interestOps(interestOps | SelectionKey.OP_WRITE); } } //清除通道选择key兴趣事件集中写操作事件 protected final void clearOpWrite() { final SelectionKey key = selectionKey(); // Check first if the key is still valid as it may be canceled as part of the deregistration // from the EventLoop // See https://github.com/netty/netty/issues/2104 if (!key.isValid()) { return; } final int interestOps = key.interestOps(); if ((interestOps & SelectionKey.OP_WRITE) != 0) { key.interestOps(interestOps & ~SelectionKey.OP_WRITE); } }
从上面可以看出,写通道Outbound缓冲区,即遍历刷新链上的写请求,如果写请求消息为
字节buf,则调用doWriteBytes完成实际数据发送操作,待子类扩展,如果写请求消息为文件Region,调用doWriteFileRegion完成实际数据发送操作,待子类扩展,数据发送,则更新通道的数据发送进度,并从刷新链上移除写请求;如果所有写请求发送完毕,则重新添加写操作事件到选择key兴趣事件集,否则继续刷新通道Outbound缓冲区中的写请求。
//过滤消息
@Override protected final Object filterOutboundMessage(Object msg) { if (msg instanceof ByteBuf) { ByteBuf buf = (ByteBuf) msg; //如果消息为direct buf,直接返回消息 if (buf.isDirect()) { return msg; } //否则包装buf为direct buf,这个newDirectBuffer方法在上一篇文章中以说 return newDirectBuffer(buf); } if (msg instanceof FileRegion) { //如果是文件Region直接返回 return msg; } throw new UnsupportedOperationException( "unsupported message type: " + StringUtil.simpleClassName(msg) + EXPECTED_TYPES); }
再看其他方法:
//获取通道元数据 @Override public ChannelMetadata metadata() { return METADATA; } /** * Shutdown the input side of the channel. 关闭通道输入流 */ protected abstract ChannelFuture shutdownInput(); //通道是否关闭输入流 protected boolean isInputShutdown0() { return false; } //创建底层通道操作类Unsafe @Override protected AbstractNioUnsafe newUnsafe() { return new NioByteUnsafe(); }
从newUnsafe方法,返回的为NioByteUnsafe
我们来看nio字节Unsafe:
protected class NioByteUnsafe extends AbstractNioUnsafe { //读操作 @Override public final void read() { //获取通道配置,Channel管道,字节buf分配器,接受字节buf分配器Handle final ChannelConfig config = config(); final ChannelPipeline pipeline = pipeline(); final ByteBufAllocator allocator = config.getAllocator(); final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle(); allocHandle.reset(config); ByteBuf byteBuf = null; boolean close = false; try { do { //分配一个字节buf byteBuf = allocHandle.allocate(allocator); //读取通道接收缓冲区数据 allocHandle.lastBytesRead(doReadBytes(byteBuf)); if (allocHandle.lastBytesRead() <= 0) { // nothing was read. release the buffer. //没有数据可读,则释放buf byteBuf.release(); byteBuf = null; close = allocHandle.lastBytesRead() < 0; break; } //更新读取消息计数器 allocHandle.incMessagesRead(1); readPending = false; //通知通道处理读取数据,触发Channel管道线的fireChannelRead事件 pipeline.fireChannelRead(byteBuf); byteBuf = null; } while (allocHandle.continueReading()); //读取操作完毕 allocHandle.readComplete(); //触发Channel管道线的fireChannelReadComplete事件 pipeline.fireChannelReadComplete(); if (close) { //如果通道关闭,关闭读操作 closeOnRead(pipeline); } } catch (Throwable t) { //处理读操作异常 handleReadException(pipeline, byteBuf, t, close, allocHandle); } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!readPending && !config.isAutoRead()) { //读操作完毕,且没有配置自动读,则从选择key兴趣集中移除读操作事件 removeReadOp(); } } } //关闭读操作 private void closeOnRead(ChannelPipeline pipeline) { if (!isInputShutdown0()) { if (Boolean.TRUE.equals(config().getOption(ChannelOption.ALLOW_HALF_CLOSURE))) { //关闭通道输入流 shutdownInput(); //触发通道输入关闭事件 pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE); } else { close(voidPromise()); } } else { //触发通道输入关闭没有数据可读取事件 pipeline.fireUserEventTriggered(ChannelInputShutdownReadComplete.INSTANCE); } } //处理读操作异常 private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close, RecvByteBufAllocator.Handle allocHandle) { if (byteBuf != null) { if (byteBuf.isReadable()) { readPending = false; //字节buf中还有数据没处理,则继续处理 pipeline.fireChannelRead(byteBuf); } else { byteBuf.release(); } } //读取操作完毕,触发Channel管道线的fireChannelReadComplete事件及fireExceptionCaught事件 allocHandle.readComplete(); pipeline.fireChannelReadComplete(); pipeline.fireExceptionCaught(cause); if (close || cause instanceof IOException) { //如果需要,关闭读操作 closeOnRead(pipeline); } } }
从上面可以看出,nio字节Unsafe读操作,从通道接收缓冲区读取数据,
通知通道处理读取数据,触发Channel管道线的fireChannelRead事件,待数据读取完毕,
触发Channel管道线的fireChannelReadComplete事件,如果在读数据的过程中,通道关闭,则
触发通道输入关闭事件(fireUserEventTriggered),如果在读数据的过程中,发生异常,则
读取缓存区中没有读完的数据,并通道通道处理剩余数据。
总结:
写通道Outbound缓冲区,即遍历刷新链上的写请求,如果写请求消息为字节buf,则调用doWriteBytes完成实际数据发送操作,待子类扩展,如果写请求消息为文件Region,调用doWriteFileRegion完成实际数据发送操作,待子类扩展,数据发送,则更新通道的数据发送进度,并从刷新链上移除写请求;如果所有写请求发送完毕,则重新添加写操作事件到选择key兴趣事件集,否则继续刷新通道Outbound缓冲区中的写请求。
nio字节Unsafe读操作,从通道接收缓冲区读取数据,通知通道处理读取数据,触发Channel管道线的fireChannelRead事件,待数据读取完毕,触发Channel管道线的fireChannelReadComplete事件,如果在读数据的过程中,通道关闭,则触发通道输入关闭事件(fireUserEventTriggered),如果在读数据的过程中,发生异常,则读取缓存区中没有读完的数据,并通道通道处理剩余数据。
附:
//ChannelMetadata
/** * Represents the properties of a {@link Channel} implementation. */ public final class ChannelMetadata { private final boolean hasDisconnect;//是否基于无连接的通信,fasle-》TCP,true-》UDP private final int defaultMaxMessagesPerRead;//每次读取,允许读取的最大消息数 /** * Create a new instance * * @param hasDisconnect {@code true} if and only if the channel has the {@code disconnect()} operation * that allows a user to disconnect and then call {@link Channel#connect(SocketAddress)} * again, such as UDP/IP. * @param defaultMaxMessagesPerRead If a {@link MaxMessagesRecvByteBufAllocator} is in use, then this value will be * set for {@link MaxMessagesRecvByteBufAllocator#maxMessagesPerRead()}. Must be {@code > 0}. */ public ChannelMetadata(boolean hasDisconnect, int defaultMaxMessagesPerRead) { if (defaultMaxMessagesPerRead <= 0) { throw new IllegalArgumentException("defaultMaxMessagesPerRead: " + defaultMaxMessagesPerRead + " (expected > 0)"); } this.hasDisconnect = hasDisconnect; this.defaultMaxMessagesPerRead = defaultMaxMessagesPerRead; } ... }
//ChannelInputShutdownReadComplete
package io.netty.channel.socket; /** * User event that signifies the channel's input side is shutdown, and we tried to shut it down again. This typically * indicates that there is no more data to read. */ public final class ChannelInputShutdownReadComplete { public static final ChannelInputShutdownReadComplete INSTANCE = new ChannelInputShutdownReadComplete(); private ChannelInputShutdownReadComplete() { } }
//ChannelInputShutdownEvent
package io.netty.channel.socket; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandler; /** * Special event which will be fired and passed to the * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)} methods once the input of * a {@link SocketChannel} was shutdown and the {@link SocketChannelConfig#isAllowHalfClosure()} method returns * {@code true}. */ public final class ChannelInputShutdownEvent { /** * Instance to use */ @SuppressWarnings("InstantiationOfUtilityClass") public static final ChannelInputShutdownEvent INSTANCE = new ChannelInputShutdownEvent(); private ChannelInputShutdownEvent() { } }
发表评论
-
netty NioSocketChannel解析
2017-09-29 12:50 1321netty 抽象BootStrap定义:http://dona ... -
netty Pooled字节buf分配器
2017-09-28 13:00 2057netty 字节buf定义:http://donald-dra ... -
netty Unpooled字节buf分配器
2017-09-26 22:01 2447netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf分配器
2017-09-26 08:43 1317netty 字节buf定义:http:// ... -
netty 复合buf概念
2017-09-25 22:31 1310netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf引用计数器
2017-09-22 12:48 1596netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf解析
2017-09-22 09:00 1844netty 通道接口定义:http://donald-drap ... -
netty 资源泄漏探测器
2017-09-21 09:37 1398netty 通道接口定义:http://donald-drap ... -
netty 字节buf定义
2017-09-20 08:31 2834netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置后续
2017-09-18 08:36 2179netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置初始化
2017-09-17 22:51 2037netty 通道接口定义:http://donald-drap ... -
netty 通道配置接口定义
2017-09-17 14:51 1079netty 通道接口定义:http://donald-drap ... -
netty NioServerSocketChannel解析
2017-09-16 13:01 1877netty ServerBootStrap解析:http:// ... -
netty 抽象nio消息通道
2017-09-15 15:30 1219netty 通道接口定义:http:/ ... -
netty 抽象nio通道解析
2017-09-14 17:23 958netty 通道接口定义:http://donald-drap ... -
netty 抽象通道后续
2017-09-13 22:40 1310netty Inboudn/Outbound通道Inv ... -
netty 通道Outbound缓冲区
2017-09-13 14:31 2191netty 通道接口定义:http:/ ... -
netty 抽象Unsafe定义
2017-09-12 21:24 1077netty 通道接口定义:http:/ ... -
netty 抽象通道初始化
2017-09-11 12:56 1857netty 管道线定义-ChannelPipeline:htt ... -
netty 通道接口定义
2017-09-10 15:36 1878netty Inboudn/Outbound通道Invoker ...
相关推荐
通过上述简单的服务端和客户端示例,我们可以看出Netty框架在服务器和客户端的代码结构上保持了一致性,都利用了ChannelHandler来处理事件,并且Netty通过一系列的接口和抽象类来提供灵活的编程模型。 Netty还提供...
1. **Channel**: 在 Netty 中,Channel 是连接到某个网络端点(如套接字)的抽象表示。它是网络 I/O 操作的基础,你可以通过 Channel 进行读写操作。 2. **EventLoop 和 EventLoopGroup**: EventLoop 是执行任务和...
Netty的ByteBuf是一个灵活的可扩展的缓冲区,其抽象了字节序列并支持自动扩容以及内存回收等优化操作,显著降低了内存泄漏的风险。 Netty4用户手册还介绍了如何使用Netty实现基础的网络应用,例如抛弃服务器、应答...
- **NIO(Non-blocking I/O)**:Netty基于Java NIO构建,实现了非阻塞的I/O模型,使得在高并发场景下性能优异。 - **Channel与Pipeline**:Channel是网络连接的抽象,负责读写数据;Pipeline则是一系列处理I/O...
Netty 是由 JBoss 组织开源的一个网络通信框架,基于 Java NIO(非阻塞I/O)构建,提供了一套高度抽象和优化的 API,使得开发者可以轻松地处理网络连接的各种复杂情况。Netty 提供了多种传输类型,如 TCP、UDP 以及...
Netty 的核心组件包括EventLoop(事件循环)、Channel(通道)、Handler(处理器)等,它们协同工作,实现了事件驱动的网络通信。 1. **EventLoop**:Netty 的事件循环是线程模型的基础,它负责接收和处理I/O事件。...
Netty 的核心组件包括:ByteBuf(字节缓冲区)、Channel(通道)、EventLoop(事件循环)、Pipeline(处理链)以及Handler(处理器)。ByteBuf 提供了一种高效的方式来处理网络数据,避免了 Java 原生字节数组操作中...
通道是网络连接的抽象,可以代表TCP连接、UDP套接字或者本地进程间通信。事件处理器则是处理与通道相关的事件,如读取、写入、连接和关闭等。Netty通过责任链模式来组织这些处理器,形成了所谓的“处理器管道...
1. **异步事件驱动**:Netty基于非阻塞I/O模型,利用Java NIO库,实现了高效的网络通信。通过事件循环(EventLoop)和事件处理器(ChannelHandler),Netty能够处理大量并发连接,显著提高系统的吞吐量。 2. **...
Netty提供了丰富的ChannelHandler(通道处理器)和ByteBuf(字节缓冲区)等组件,使得开发人员可以方便地处理各种网络协议,包括HTTP和FTP等涉及文件传输的协议。在文件上传场景下,服务器端通常需要创建一个...
Netty提供了一种更高级别的抽象,使得网络编程变得更加简单和灵活。 **多线程并发**: 多线程并发是Java的核心特性之一,允许程序同时执行多个任务。通过使用Thread类或实现Runnable接口,可以创建并启动新的线程。...
Netty是一个基于NIO的网络编程框架,提供了高度优化的异步事件驱动网络应用程序框架,用于快速开发可维护的高性能服务器和客户端。Netty简化了NIO的复杂性,使得开发者可以更容易地编写出高效、可靠的网络应用。 ...
3. **ByteBuf**:Netty自定义的字节缓冲区,相比于Java的`ByteBuffer`,它提供了更高效且方便的操作方式,如预读、预写等,避免了不必要的内存复制。 4. **编码与解码**:Netty提供了丰富的编解码器,如...
2. **Channel**:在 Netty 中,Channel 是连接到某个网络端点的抽象,它可以读写数据。例如,Socket 或者 UDP 的 DatagramChannel。 3. **Pipeline**:ChannelHandler 组成的链路,用于处理入站和出站事件。这使得 ...
4. **ByteBuf**:Netty提供的高效字节缓冲区,提供了比Java的ByteBuffer更易用和高效的API,支持零拷贝和内存池管理。 5. **Decoder** 和 **Encoder**:用于在网络数据和应用对象之间进行编码和解码,例如将HTTP请求...
Netty基于NIO进行了优化和封装,提供了更高级别的抽象,使得网络编程变得更加简单。Netty中的关键概念包括: 1. **Channel**:Netty的网络操作抽象类,代表一个到另一端点的连接。它支持多种I/O操作,如绑定、连接...
Netty 提供了一种简化网络编程的方式,通过提供高级抽象层,如 ByteBuf(用于高效的数据处理)、Channel(表示网络连接)和 ChannelHandlerContext(作为处理事件和调用处理程序的方法)。这些组件使得开发者可以...
1. **ByteBuf**:这是Netty的核心数据结构,用于高效地处理网络I/O中的字节流。它提供了一种灵活且高性能的方式来存储和操作二进制数据,支持零拷贝,减少了不必要的内存复制,提高了性能。 2. **Zero-Copy**:...
- ByteBuf:Netty自定义的字节缓冲区,比Java NIO的ByteBuffer更易用且性能优秀。 2. **Netty的Channel和Pipeline** - Channel:Netty中的网络连接抽象,负责读写数据。 - ChannelHandlerContext:在Pipeline中...
Netty 在 Socket 基础上提供了更高级别的抽象,使得开发者可以更高效地处理网络数据流。 在 Netty 中,"第七章:编解码器Codec" 是一个关键部分,主要讨论了如何处理网络通信中的数据编码与解码问题。编解码器是 ...