1 /* 2 * Copyright 2012 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package org.jboss.netty.channel.socket.nio; 17 18 import java.nio.channels.Selector; 19 import java.util.concurrent.Executor; 20 import java.util.concurrent.Executors; 21 import java.util.concurrent.RejectedExecutionException; 22 23 import org.jboss.netty.channel.ChannelPipeline; 24 import org.jboss.netty.channel.group.ChannelGroup; 25 import org.jboss.netty.channel.socket.DatagramChannel; 26 import org.jboss.netty.channel.socket.DatagramChannelFactory; 27 import org.jboss.netty.channel.socket.InternetProtocolFamily; 28 import org.jboss.netty.channel.socket.Worker; 29 import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory; 30 import org.jboss.netty.util.ExternalResourceReleasable; 31 32 /** 33 * A {@link DatagramChannelFactory} that creates a NIO-based connectionless 34 * {@link DatagramChannel}. It utilizes the non-blocking I/O mode which 35 * was introduced with NIO to serve many number of concurrent connections 36 * efficiently. 37 * 38 * <h3>How threads work</h3> 39 * <p> 40 * There is only one thread type in a {@link NioDatagramChannelFactory}; 41 * worker threads. 42 * 43 * <h4>Worker threads</h4> 44 * <p> 45 * One {@link NioDatagramChannelFactory} can have one or more worker 46 * threads. A worker thread performs non-blocking read and write for one or 47 * more {@link DatagramChannel}s in a non-blocking mode. 48 * 49 * <h3>Life cycle of threads and graceful shutdown</h3> 50 * <p> 51 * All worker threads are acquired from the {@link Executor} which was specified 52 * when a {@link NioDatagramChannelFactory} was created. Therefore, you should 53 * make sure the specified {@link Executor} is able to lend the sufficient 54 * number of threads. It is the best bet to specify 55 * {@linkplain Executors#newCachedThreadPool() a cached thread pool}. 56 * <p> 57 * All worker threads are acquired lazily, and then released when there's 58 * nothing left to process. All the related resources such as {@link Selector} 59 * are also released when the worker threads are released. Therefore, to shut 60 * down a service gracefully, you should do the following: 61 * 62 * <ol> 63 * <li>close all channels created by the factory usually using 64 * {@link ChannelGroup#close()}, and</li> 65 * <li>call {@link #releaseExternalResources()}.</li> 66 * </ol> 67 * 68 * Please make sure not to shut down the executor until all channels are 69 * closed. Otherwise, you will end up with a {@link RejectedExecutionException} 70 * and the related resources might not be released properly. 71 * 72 * <h3>Limitation</h3> 73 * <p> 74 * Multicast is not supported. Please use {@link OioDatagramChannelFactory} 75 * instead. 76 * 77 * @apiviz.landmark 78 */ 79 public class NioDatagramChannelFactory implements DatagramChannelFactory { 80 81 private final NioDatagramPipelineSink sink; 82 private final WorkerPool<NioDatagramWorker> workerPool; 83 private final InternetProtocolFamily family; 84 85 /** 86 * Create a new {@link NioDatagramChannelFactory} with a {@link Executors#newCachedThreadPool()} 87 * and without preferred {@link InternetProtocolFamily}. Please note that the {@link InternetProtocolFamily} 88 * of the channel will be platform (and possibly configuration) dependent and therefore 89 * unspecified. Use {@link #NioDatagramChannelFactory(InternetProtocolFamily)} if unsure. 90 * 91 * See {@link #NioDatagramChannelFactory(Executor)} 92 */ 93 public NioDatagramChannelFactory() { 94 this(Executors.newCachedThreadPool(), null); 95 } 96 97 /** 98 * Create a new {@link NioDatagramChannelFactory} with a {@link Executors#newCachedThreadPool()}. 99 * 100 * See {@link #NioDatagramChannelFactory(Executor)} 101 */ 102 public NioDatagramChannelFactory(InternetProtocolFamily family) { 103 this(Executors.newCachedThreadPool(), family); 104 } 105 106 /** 107 * Creates a new instance. Calling this constructor is same with calling 108 * {@link #NioDatagramChannelFactory(Executor, int)} with 2 * the number of 109 * available processors in the machine. The number of available processors 110 * is obtained by {@link Runtime#availableProcessors()}. 111 * <p> 112 * Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly 113 * configuration) dependent and therefore unspecified. 114 * Use {@link #NioDatagramChannelFactory(Executor, InternetProtocolFamily)} if unsure. 115 * 116 * @param workerExecutor 117 * the {@link Executor} which will execute the I/O worker threads 118 */ 119 public NioDatagramChannelFactory(final Executor workerExecutor) { 120 this(workerExecutor, SelectorUtil.DEFAULT_IO_THREADS); 121 } 122 123 /** 124 * Creates a new instance. 125 * <p> 126 * Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly 127 * configuration) dependent and therefore unspecified. 128 * Use {@link #NioDatagramChannelFactory(Executor, int, InternetProtocolFamily)} if unsure. 129 * 130 * @param workerExecutor 131 * the {@link Executor} which will execute the I/O worker threads 132 * @param workerCount 133 * the maximum number of I/O worker threads 134 */ 135 public NioDatagramChannelFactory(final Executor workerExecutor, final int workerCount) { 136 this(new NioDatagramWorkerPool(workerExecutor, workerCount)); 137 } 138 139 /** 140 * Creates a new instance. 141 * <p> 142 * Please note that the {@link InternetProtocolFamily} of the channel will be platform (and possibly 143 * configuration) dependent and therefore unspecified. 144 * Use {@link #NioDatagramChannelFactory(WorkerPool, InternetProtocolFamily)} if unsure. 145 * 146 * @param workerPool 147 * the {@link WorkerPool} which will be used to obtain the {@link NioDatagramWorker} that execute 148 * the I/O worker threads 149 */ 150 public NioDatagramChannelFactory(WorkerPool<NioDatagramWorker> workerPool) { 151 this(workerPool, null); 152 } 153 154 /** 155 * Creates a new instance. Calling this constructor is same with calling 156 * {@link #NioDatagramChannelFactory(Executor, int)} with 2 * the number of 157 * available processors in the machine. The number of available processors 158 * is obtained by {@link Runtime#availableProcessors()}. 159 * 160 * @param workerExecutor 161 * the {@link Executor} which will execute the I/O worker threads 162 * @param family 163 * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. 164 * <strong>Be aware that this option is only considered when running on java7+</strong> 165 */ 166 public NioDatagramChannelFactory(final Executor workerExecutor, InternetProtocolFamily family) { 167 this(workerExecutor, SelectorUtil.DEFAULT_IO_THREADS, family); 168 } 169 170 /** 171 * Creates a new instance. 172 * 173 * @param workerExecutor 174 * the {@link Executor} which will execute the I/O worker threads 175 * @param workerCount 176 * the maximum number of I/O worker threads 177 * @param family 178 * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. 179 * <strong>Be aware that this option is only considered when running on java7+</strong> 180 */ 181 public NioDatagramChannelFactory(final Executor workerExecutor, 182 final int workerCount, InternetProtocolFamily family) { 183 this(new NioDatagramWorkerPool(workerExecutor, workerCount), family); 184 } 185 186 /** 187 * Creates a new instance. 188 * 189 * @param workerPool 190 * the {@link WorkerPool} which will be used to obtain the {@link Worker} that execute 191 * the I/O worker threads 192 * @param family 193 * the {@link InternetProtocolFamily} to use. This should be used for UDP multicast. 194 * <strong>Be aware that this option is only considered when running on java7+</strong> 195 */ 196 public NioDatagramChannelFactory(WorkerPool<NioDatagramWorker> workerPool, InternetProtocolFamily family) { 197 this.workerPool = workerPool; 198 this.family = family; 199 sink = new NioDatagramPipelineSink(workerPool); 200 } 201 202 public DatagramChannel newChannel(final ChannelPipeline pipeline) { 203 return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker(), family); 204 } 205 206 public void releaseExternalResources() { 207 if (workerPool instanceof ExternalResourceReleasable) { 208 ((ExternalResourceReleasable) workerPool).releaseExternalResources(); 209 } 210 } 211 }