- 浏览: 980945 次
文章分类
- 全部博客 (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 管道线定义-ChannelPipeline:http://donald-draper.iteye.com/blog/2388453
netty 默认Channel管道线初始化:http://donald-draper.iteye.com/blog/2388613
netty 默认Channel管道线-添加通道处理器:http://donald-draper.iteye.com/blog/2388726
netty 默认Channel管道线-通道处理器移除与替换:http://donald-draper.iteye.com/blog/2388793
netty 默认Channel管道线-Inbound和Outbound事件处理:http://donald-draper.iteye.com/blog/2389148
netty 通道接口定义:http://donald-draper.iteye.com/blog/2392740
引言:
前一篇文章,我们看了通道接口的定义,先来回顾一下:
通道Channel,关联一个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器;一个字节buf分配器ByteBufAllocator,用于分配字节buf,还有一些获取通道状态的方式,是否注册到事件循环,通道是否打开,是否可写;另外还要获取通道配置ChannelConfig,通道元数据ChannelMetadata的方法;最重要的是,关联一个Unsafe,用于通道的地址绑定,连接操作以及断开,通道的读写,注册到事件循环以及反注册。
今天我们来看一下通道接口的抽象实现AbstractChannel :
从上面可以看出,抽象通道内部关联一个硬件底层操作类Unsafe,个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器,默认为DefaultChannelPipeline。
我们来简单看一下几个通道关闭异常定义:
//ThrowableUtil
我们来看一下unknownStackTrace方法的设置异常的堆栈元素这一句:
//Throwable
//StackTraceElement
简单看了一下,异常工具类,我们回到抽象通道,来看一下构造:
上面两个构造关键是一下几点
1.
2.
3.
我们分别来看这几点:
1.
//DefaultChannelId
具体id的生成见附。
先来看第3点:
3.
默认Channel管道线为DefaultChannelPipeline。
再来看:创建底层操作类unsafe
2.
在第二点中上述方法返回的是抽象Unsafe,我们来看一下AbstractUnsafe的实现:
抽象通道内部类抽象Unsafe由于篇幅问题,我们单用一篇文章来说:
抽象Unsafe解析:
从上面可以看出通道构造主要是初始化通道所属父通道,通道id,底层操作类Unsafe,Channel管道线程,默认的Channel管道线为DefaultChannelPipeline,底层操作类Unsafe为AbstractUnsafe。
总结:
抽象通道AbstractChannel内部关联一个硬件底层操作类Unsafe,个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器,默认为DefaultChannelPipeline。通道构造主要是初始化通道所属父通道,通道id,底层操作类Unsafe,Channel管道线程,默认的Channel管道线为DefaultChannelPipeline,底层操作类Unsafe为AbstractUnsafe。
附:
//DefaultChannelId
netty 默认Channel管道线初始化:http://donald-draper.iteye.com/blog/2388613
netty 默认Channel管道线-添加通道处理器:http://donald-draper.iteye.com/blog/2388726
netty 默认Channel管道线-通道处理器移除与替换:http://donald-draper.iteye.com/blog/2388793
netty 默认Channel管道线-Inbound和Outbound事件处理:http://donald-draper.iteye.com/blog/2389148
netty 通道接口定义:http://donald-draper.iteye.com/blog/2392740
引言:
前一篇文章,我们看了通道接口的定义,先来回顾一下:
通道Channel,关联一个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器;一个字节buf分配器ByteBufAllocator,用于分配字节buf,还有一些获取通道状态的方式,是否注册到事件循环,通道是否打开,是否可写;另外还要获取通道配置ChannelConfig,通道元数据ChannelMetadata的方法;最重要的是,关联一个Unsafe,用于通道的地址绑定,连接操作以及断开,通道的读写,注册到事件循环以及反注册。
今天我们来看一下通道接口的抽象实现AbstractChannel :
package io.netty.channel; import io.netty.buffer.ByteBufAllocator; import io.netty.util.DefaultAttributeMap; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.ThrowableUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.NoRouteToHostException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.ClosedChannelException; import java.nio.channels.NotYetConnectedException; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; /** * A skeletal {@link Channel} implementation. */ public abstract class AbstractChannel extends DefaultAttributeMap implements Channel { private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractChannel.class); private static final ClosedChannelException FLUSH0_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractUnsafe.class, "flush0()");//flush0方法调用时,通道关闭异常 private static final ClosedChannelException ENSURE_OPEN_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractUnsafe.class, "ensureOpen(...)");//确保通道打开方法调用时,通道关闭异常 private static final ClosedChannelException CLOSE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractUnsafe.class, "close(...)");//close方法调用时,通道关闭异常 private static final ClosedChannelException WRITE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractUnsafe.class, "write(...)");//write方法调用时,通道关闭异常 private static final NotYetConnectedException FLUSH0_NOT_YET_CONNECTED_EXCEPTION = ThrowableUtil.unknownStackTrace( new NotYetConnectedException(), AbstractUnsafe.class, "flush0()");//flush0方法调用时,通道还未连接异常 private final Channel parent;//所属通道 private final ChannelId id;//通道id private final Unsafe unsafe;//硬件底层操作类 private final DefaultChannelPipeline pipeline;//Channel管道 private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);//空异步任务 private final CloseFuture closeFuture = new CloseFuture(this);//异步关闭任务 private volatile SocketAddress localAddress;//本地socket地址 private volatile SocketAddress remoteAddress;//远端socket地址 private volatile EventLoop eventLoop;//通道注册的事件循环 private volatile boolean registered;//是否注册 /** Cache for the string representation of this channel */ private boolean strValActive; private String strVal; ... }
从上面可以看出,抽象通道内部关联一个硬件底层操作类Unsafe,个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器,默认为DefaultChannelPipeline。
我们来简单看一下几个通道关闭异常定义:
private static final ClosedChannelException FLUSH0_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace( new ClosedChannelException(), AbstractUnsafe.class, "flush0()");//flush0方法调用时,通道关闭异常
//ThrowableUtil
package io.netty.util.internal; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; public final class ThrowableUtil { private ThrowableUtil() { } /** * Set the {@link StackTraceElement} for the given {@link Throwable}, using the {@link Class} and method name. 设置异常的堆栈元素为给定的类和方法名 */ public static <T extends Throwable> T unknownStackTrace(T cause, Class<?> clazz, String method) { //设置异常的堆栈元素 cause.setStackTrace(new StackTraceElement[] { new StackTraceElement(clazz.getName(), method, null, -1)}); return cause; } /** * Gets the stack trace from a Throwable as a String. *将Throwable堆栈信息,转换为字符串 * @param cause the {@link Throwable} to be examined * @return the stack trace as generated by {@link Throwable#printStackTrace(java.io.PrintWriter)} method. */ public static String stackTraceToString(Throwable cause) { ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintStream pout = new PrintStream(out); cause.printStackTrace(pout); pout.flush(); try { return new String(out.toByteArray()); } finally { try { out.close(); } catch (IOException ignore) { // ignore as should never happen } } } }
我们来看一下unknownStackTrace方法的设置异常的堆栈元素这一句:
//设置异常的堆栈元素 cause.setStackTrace(new StackTraceElement[] { new StackTraceElement(clazz.getName(), method, null, -1)});
//Throwable
/** * Sets the stack trace elements that will be returned by * {@link #getStackTrace()} and printed by {@link #printStackTrace()} * and related methods. 设置异常的堆栈元素,将会被#getStackTrace方法返回,#printStackTrace打印 * * This method, which is designed for use by RPC frameworks and other * advanced systems, allows the client to override the default * stack trace that is either generated by {@link #fillInStackTrace()} * when a throwable is constructed or deserialized when a throwable is * read from a serialization stream. 此方法,为RPC框架和高级系统而设计,当异常通过#fillInStackTrace构造, 或当异常从序列化流读取时,反序列化异常堆栈信息时,允许客户端重写默认的堆栈信息。 * * <p>If the stack trace of this {@code Throwable} {@linkplain * Throwable#Throwable(String, Throwable, boolean, boolean) is not * writable}, calling this method has no effect other than * validating its argument. 如果异常#Throwable返回的结果,即异常不可写,则调用此方法没有任何影响 * * @param stackTrace the stack trace elements to be associated with * this {@code Throwable}. The specified array is copied by this * call; changes in the specified array after the method invocation * returns will have no affect on this {@code Throwable}'s stack * trace. 设置异常堆栈元素。堆栈元素数组,是拷贝调用,改变参数,不会影响异常的 堆栈信息。 * * @throws NullPointerException if {@code stackTrace} is * {@code null} or if any of the elements of * {@code stackTrace} are {@code null} * * @since 1.4 */ public void setStackTrace(StackTraceElement[] stackTrace) { // Validate argument 验证堆栈元素 StackTraceElement[] defensiveCopy = stackTrace.clone(); for (int i = 0; i < defensiveCopy.length; i++) { if (defensiveCopy[i] == null) throw new NullPointerException("stackTrace[" + i + "]"); } synchronized (this) { if (this.stackTrace == null && // Immutable stack backtrace == null) // Test for out of protocol state return; //设置异常堆栈元素 this.stackTrace = defensiveCopy; } }
//StackTraceElement
public final class StackTraceElement implements java.io.Serializable { // Normally initialized by VM (public constructor added in 1.5) //异常发生类,方法名,文件名,及行号 private String declaringClass; private String methodName; private String fileName; private int lineNumber; ... }
简单看了一下,异常工具类,我们回到抽象通道,来看一下构造:
/** * Creates a new instance. * * @param parent * the parent of this channel. {@code null} if there's no parent. */ protected AbstractChannel(Channel parent) { this.parent = parent; //创建通道id id = newId(); //创建底层操作类unsafe unsafe = newUnsafe(); //新建Channel管道 pipeline = newChannelPipeline(); } /** * Creates a new instance. * * @param parent * the parent of this channel. {@code null} if there's no parent. */ protected AbstractChannel(Channel parent, ChannelId id) { this.parent = parent; this.id = id; unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
上面两个构造关键是一下几点
1.
//创建通道id id = newId();
2.
//创建底层操作类unsafe unsafe = newUnsafe();
3.
//新建Channel管道 pipeline = newChannelPipeline();
我们分别来看这几点:
1.
//创建通道id id = newId();
/** * Returns a new {@link DefaultChannelId} instance. Subclasses may override this method to assign custom * {@link ChannelId}s to {@link Channel}s that use the {@link AbstractChannel#AbstractChannel(Channel)} constructor. */ protected ChannelId newId() { return DefaultChannelId.newInstance(); }
//DefaultChannelId
public final class DefaultChannelId implements ChannelId { private static final long serialVersionUID = 3884076183504074063L; private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelId.class); private static final byte[] MACHINE_ID;//机器id private static final int PROCESS_ID_LEN = 4;//netty进程id长度 private static final int PROCESS_ID;//netty进程id private static final int SEQUENCE_LEN = 4;//序列号长度 private static final int TIMESTAMP_LEN = 8;//事件戳长度 private static final int RANDOM_LEN = 4;//随机长度 private static final AtomicInteger nextSequence = new AtomicInteger();//序列号产生id private final byte[] data;//id数据 private final int hashCode;//哈希code private transient String shortValue;//短id private transient String longValue;//长id @Override public String asShortText() { String shortValue = this.shortValue; if (shortValue == null) { this.shortValue = shortValue = ByteBufUtil.hexDump(data, data.length - RANDOM_LEN, RANDOM_LEN); } return shortValue; } @Override public String asLongText() { String longValue = this.longValue; if (longValue == null) { this.longValue = longValue = newLongValue(); } return longValue; } private String newLongValue() { StringBuilder buf = new StringBuilder(2 * data.length + 5); int i = 0; i = appendHexDumpField(buf, i, MACHINE_ID.length); i = appendHexDumpField(buf, i, PROCESS_ID_LEN); i = appendHexDumpField(buf, i, SEQUENCE_LEN); i = appendHexDumpField(buf, i, TIMESTAMP_LEN); i = appendHexDumpField(buf, i, RANDOM_LEN); assert i == data.length; return buf.substring(0, buf.length() - 1); } ... }
具体id的生成见附。
先来看第3点:
3.
//新建Channel管道 pipeline = newChannelPipeline();
/** * Returns a new {@link DefaultChannelPipeline} instance. */ protected DefaultChannelPipeline newChannelPipeline() { return new DefaultChannelPipeline(this); }
默认Channel管道线为DefaultChannelPipeline。
再来看:创建底层操作类unsafe
2.
//创建底层操作类unsafe unsafe = newUnsafe();
/** * Create a new {@link AbstractUnsafe} instance which will be used for the life-time of the {@link Channel} //待子类实现 */ protected abstract AbstractUnsafe newUnsafe();
在第二点中上述方法返回的是抽象Unsafe,我们来看一下AbstractUnsafe的实现:
抽象通道内部类抽象Unsafe由于篇幅问题,我们单用一篇文章来说:
抽象Unsafe解析:
从上面可以看出通道构造主要是初始化通道所属父通道,通道id,底层操作类Unsafe,Channel管道线程,默认的Channel管道线为DefaultChannelPipeline,底层操作类Unsafe为AbstractUnsafe。
总结:
抽象通道AbstractChannel内部关联一个硬件底层操作类Unsafe,个事件循环,即通道注册的事件循环EventLoop,一个Channel管道ChannelPipeline,用于存放通道处理器,默认为DefaultChannelPipeline。通道构造主要是初始化通道所属父通道,通道id,底层操作类Unsafe,Channel管道线程,默认的Channel管道线为DefaultChannelPipeline,底层操作类Unsafe为AbstractUnsafe。
附:
//DefaultChannelId
package io.netty.channel; import io.netty.buffer.ByteBufUtil; import io.netty.util.internal.EmptyArrays; import io.netty.util.internal.MacAddressUtil; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.lang.reflect.Method; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import static io.netty.util.internal.MacAddressUtil.defaultMachineId; import static io.netty.util.internal.MacAddressUtil.parseMAC; /** * The default {@link ChannelId} implementation. */ public final class DefaultChannelId implements ChannelId { private static final long serialVersionUID = 3884076183504074063L; private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelId.class); private static final byte[] MACHINE_ID; private static final int PROCESS_ID_LEN = 4; private static final int PROCESS_ID; private static final int SEQUENCE_LEN = 4; private static final int TIMESTAMP_LEN = 8; private static final int RANDOM_LEN = 4; private static final AtomicInteger nextSequence = new AtomicInteger(); /** * Returns a new {@link DefaultChannelId} instance. */ public static DefaultChannelId newInstance() { return new DefaultChannelId(); } static { int processId = -1; String customProcessId = SystemPropertyUtil.get("io.netty.processId"); if (customProcessId != null) { try { processId = Integer.parseInt(customProcessId); } catch (NumberFormatException e) { // Malformed input. } if (processId < 0) { processId = -1; logger.warn("-Dio.netty.processId: {} (malformed)", customProcessId); } else if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.processId: {} (user-set)", processId); } } if (processId < 0) { processId = defaultProcessId(); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.processId: {} (auto-detected)", processId); } } PROCESS_ID = processId; byte[] machineId = null; String customMachineId = SystemPropertyUtil.get("io.netty.machineId"); if (customMachineId != null) { try { machineId = parseMAC(customMachineId); } catch (Exception e) { logger.warn("-Dio.netty.machineId: {} (malformed)", customMachineId, e); } if (machineId != null) { logger.debug("-Dio.netty.machineId: {} (user-set)", customMachineId); } } if (machineId == null) { machineId = defaultMachineId(); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.machineId: {} (auto-detected)", MacAddressUtil.formatAddress(machineId)); } } MACHINE_ID = machineId; } private static int defaultProcessId() { ClassLoader loader = null; String value; try { loader = PlatformDependent.getClassLoader(DefaultChannelId.class); // Invoke java.lang.management.ManagementFactory.getRuntimeMXBean().getName() Class<?> mgmtFactoryType = Class.forName("java.lang.management.ManagementFactory", true, loader); Class<?> runtimeMxBeanType = Class.forName("java.lang.management.RuntimeMXBean", true, loader); Method getRuntimeMXBean = mgmtFactoryType.getMethod("getRuntimeMXBean", EmptyArrays.EMPTY_CLASSES); Object bean = getRuntimeMXBean.invoke(null, EmptyArrays.EMPTY_OBJECTS); Method getName = runtimeMxBeanType.getMethod("getName", EmptyArrays.EMPTY_CLASSES); value = (String) getName.invoke(bean, EmptyArrays.EMPTY_OBJECTS); } catch (Throwable t) { logger.debug("Could not invoke ManagementFactory.getRuntimeMXBean().getName(); Android?", t); try { // Invoke android.os.Process.myPid() Class<?> processType = Class.forName("android.os.Process", true, loader); Method myPid = processType.getMethod("myPid", EmptyArrays.EMPTY_CLASSES); value = myPid.invoke(null, EmptyArrays.EMPTY_OBJECTS).toString(); } catch (Throwable t2) { logger.debug("Could not invoke Process.myPid(); not Android?", t2); value = ""; } } int atIndex = value.indexOf('@'); if (atIndex >= 0) { value = value.substring(0, atIndex); } int pid; try { pid = Integer.parseInt(value); } catch (NumberFormatException e) { // value did not contain an integer. pid = -1; } if (pid < 0) { pid = PlatformDependent.threadLocalRandom().nextInt(); logger.warn("Failed to find the current process ID from '{}'; using a random value: {}", value, pid); } return pid; } private final byte[] data; private final int hashCode; private transient String shortValue; private transient String longValue; private DefaultChannelId() { data = new byte[MACHINE_ID.length + PROCESS_ID_LEN + SEQUENCE_LEN + TIMESTAMP_LEN + RANDOM_LEN]; int i = 0; // machineId System.arraycopy(MACHINE_ID, 0, data, i, MACHINE_ID.length); i += MACHINE_ID.length; // processId i = writeInt(i, PROCESS_ID); // sequence i = writeInt(i, nextSequence.getAndIncrement()); // timestamp (kind of) i = writeLong(i, Long.reverse(System.nanoTime()) ^ System.currentTimeMillis()); // random int random = PlatformDependent.threadLocalRandom().nextInt(); i = writeInt(i, random); assert i == data.length; hashCode = Arrays.hashCode(data); } private int writeInt(int i, int value) { data[i ++] = (byte) (value >>> 24); data[i ++] = (byte) (value >>> 16); data[i ++] = (byte) (value >>> 8); data[i ++] = (byte) value; return i; } private int writeLong(int i, long value) { data[i ++] = (byte) (value >>> 56); data[i ++] = (byte) (value >>> 48); data[i ++] = (byte) (value >>> 40); data[i ++] = (byte) (value >>> 32); data[i ++] = (byte) (value >>> 24); data[i ++] = (byte) (value >>> 16); data[i ++] = (byte) (value >>> 8); data[i ++] = (byte) value; return i; } @Override public String asShortText() { String shortValue = this.shortValue; if (shortValue == null) { this.shortValue = shortValue = ByteBufUtil.hexDump(data, data.length - RANDOM_LEN, RANDOM_LEN); } return shortValue; } @Override public String asLongText() { String longValue = this.longValue; if (longValue == null) { this.longValue = longValue = newLongValue(); } return longValue; } private String newLongValue() { StringBuilder buf = new StringBuilder(2 * data.length + 5); int i = 0; i = appendHexDumpField(buf, i, MACHINE_ID.length); i = appendHexDumpField(buf, i, PROCESS_ID_LEN); i = appendHexDumpField(buf, i, SEQUENCE_LEN); i = appendHexDumpField(buf, i, TIMESTAMP_LEN); i = appendHexDumpField(buf, i, RANDOM_LEN); assert i == data.length; return buf.substring(0, buf.length() - 1); } private int appendHexDumpField(StringBuilder buf, int i, int length) { buf.append(ByteBufUtil.hexDump(data, i, length)); buf.append('-'); i += length; return i; } @Override public int hashCode() { return hashCode; } @Override public int compareTo(final ChannelId o) { if (this == o) { // short circuit return 0; } if (o instanceof DefaultChannelId) { // lexicographic comparison final byte[] otherData = ((DefaultChannelId) o).data; int len1 = data.length; int len2 = otherData.length; int len = Math.min(len1, len2); for (int k = 0; k < len; k++) { byte x = data[k]; byte y = otherData[k]; if (x != y) { // treat these as unsigned bytes for comparison return (x & 0xff) - (y & 0xff); } } return len1 - len2; } return asLongText().compareTo(o.asLongText()); } @Override public boolean equals(Object obj) { return this == obj || (obj instanceof DefaultChannelId && Arrays.equals(data, ((DefaultChannelId) obj).data)); } @Override public String toString() { return asShortText(); } }
发表评论
-
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 2443netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf分配器
2017-09-26 08:43 1316netty 字节buf定义:http:// ... -
netty 复合buf概念
2017-09-25 22:31 1310netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf引用计数器
2017-09-22 12:48 1593netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf解析
2017-09-22 09:00 1843netty 通道接口定义:http://donald-drap ... -
netty 资源泄漏探测器
2017-09-21 09:37 1397netty 通道接口定义:http://donald-drap ... -
netty 字节buf定义
2017-09-20 08:31 2833netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置后续
2017-09-18 08:36 2177netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置初始化
2017-09-17 22:51 2036netty 通道接口定义:http://donald-drap ... -
netty 通道配置接口定义
2017-09-17 14:51 1077netty 通道接口定义:http://donald-drap ... -
netty NioServerSocketChannel解析
2017-09-16 13:01 1876netty ServerBootStrap解析:http:// ... -
netty 抽象nio消息通道
2017-09-15 15:30 1217netty 通道接口定义:http:/ ... -
netty 抽象nio字节通道
2017-09-14 22:39 1201netty 通道接口定义:http:/ ... -
netty 抽象nio通道解析
2017-09-14 17:23 957netty 通道接口定义:http://donald-drap ... -
netty 抽象通道后续
2017-09-13 22:40 1309netty Inboudn/Outbound通道Inv ... -
netty 通道Outbound缓冲区
2017-09-13 14:31 2189netty 通道接口定义:http:/ ... -
netty 抽象Unsafe定义
2017-09-12 21:24 1075netty 通道接口定义:http:/ ... -
netty 通道接口定义
2017-09-10 15:36 1876netty Inboudn/Outbound通道Invoker ...
相关推荐
channelRead0() 方法用于处理接收到的客户端消息,而channelActive() 方法在客户端连接建立后被调用,适合在这个时候发送欢迎消息或进行其他初始化操作。 在实际的代码实现中,我们可能还需要定义自定义的Message...
5. **Bootstrap**: Bootstrap 类用于初始化服务器端(ServerBootstrap)或客户端(Bootstrap)的配置,包括选择器、事件循环组、通道类等。 6. **Codec**: Netty 提供了一系列的编解码器,用于将各种数据类型转换为...
Bootstrap负责初始化和配置网络连接,Channel是网络I/O操作的抽象,EventLoop负责监听和处理事件,而Pipeline则是一系列处理器的链,每个处理器处理特定类型的事件或数据。 Netty的非阻塞I/O模型允许它在高并发环境...
2. **通道初始化(ChannelInitializer)**:在初始化器中,我们添加所需的处理器到通道管道,如解码器、编码器和业务处理器。 3. **连接处理**:当客户端连接到服务器时,会触发ChannelActive事件,我们可以在这个...
- 配置与初始化:通过Bootstrap和ServerBootstrap配置网络连接参数,构建ChannelPipeline。 4. **Netty的异步I/O** - NIO基础:Netty基于Java NIO API,提供了更高级别的抽象。 - Selectors与多路复用:Netty...
- 初始化EventLoopGroup:创建一个ClientBootstrap的EventLoopGroup。 - 配置ClientBootstrap:设置Channel、Handler链等。 - 连接服务器:调用connect方法发起连接。 **5. 自定义Handler** - 实现...
- **Bootstrap**: 用于初始化和配置服务器或客户端的配置信息。 - **Pipeline**: 通道处理链,每个连接都有一个pipeline,其中包含多个处理器(Handler)来处理进来的数据。 - **EventLoop**: 负责执行事件处理的...
2. **ServerBootstrap**: Netty提供的专门用于服务器的Bootstrap,它可以配置通道初始化器,用于创建并初始化每个新连接的ChannelPipeline。 3. **Channel**: 表示网络连接的抽象,可以是TCP连接、UDP连接或者其他...
2. **Bootstrap**: 用于初始化和配置服务器或客户端的类。它包含了用于连接、绑定和配置通道的参数。 3. **Handler**: 处理网络事件和数据传输的接口或抽象类。你可以创建自定义的处理器来执行业务逻辑。 4. **...
Bootstrap是Netty中的一个启动类,用于配置并初始化Netty服务。它有两个主要实现:`Bootstrap`和`ServerBootstrap`,分别用于客户端和服务端的初始化。 #### 类AbstractBootstrap 这是一个抽象基类,为`Bootstrap`...
Bootstrap则是用来创建和初始化服务器或客户端连接的工具类。 总的来说,这份《Netty权威指南第二版》的源代码是一个深入理解Netty内部工作原理、学习如何构建高效网络应用的宝贵资源。通过实际操作和学习这些代码...
1. **初始化ServerBootstrap**:Netty服务器的启动过程通常从创建ServerBootstrap实例开始,设置其配置,如BossGroup(接收新连接的线程组)和WorkerGroup(处理I/O事件的线程组)。 2. **定义Pipeline**:Pipeline...
本章详细阐述如何初始化和启动Netty服务器和客户端,包括Bootstrap、ServerBootstrap和ChannelOption的配置。 10. **第十章:安全(未提供)** Netty提供了SSL/TLS支持,这一章可能讲解如何在Netty应用中实现...
6. **Bootstrap(引导类)**:用于初始化和配置服务器或客户端。通过设置ChannelFactory、Group、Pipeline等,然后调用bind或connect方法启动服务。 7. **EventLoopGroup(事件循环组)**:一组EventLoop,每个...
- **Bootstrap**:是Netty应用启动引导类,用于初始化并启动Netty服务。 - **Channel**:是所有I/O操作的基础,可以理解为连接的抽象表示。 - **EventLoop**:负责处理I/O事件,包括注册、读取、写入等操作。 - **...
Bootstrap是客户端或服务器端的启动器,它负责配置和初始化连接;Channel是网络连接的抽象,可以代表TCP、UDP、HTTP等不同协议的连接;ChannelHandler则是处理I/O事件和数据的接口,提供了一种解耦业务逻辑和网络...
1. **服务器端搭建**:使用ServerBootstrap初始化服务器,设置NioServerSocketChannel作为监听通道,配置线程池和Handler链。服务器端的Handler主要负责接收客户端连接、解码接收到的数据,并将消息转发给客户端。 ...
Bootstrap和ServerBootstrap是启动客户端和服务器的入口,它们负责配置和初始化网络连接。Channel是Netty中的基本抽象,表示一个网络连接或套接字。ChannelHandlerContext提供了与Channel交互的能力,而...
1. **连接管理器**:用于初始化连接,重新连接以及断线重连等操作。 2. **消息发送模块**:用户输入消息后,将消息封装成Netty的ByteBuf,通过Channel发送到服务器。 3. **消息接收模块**:接收服务器转发的其他...