查看本类的 API文档回源码主页即时通讯网 - 即时通讯开发者社区!
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    *   https://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 io.netty.channel.socket.nio;
17  
18  import io.netty.channel.ChannelException;
19  import io.netty.channel.ChannelMetadata;
20  import io.netty.channel.ChannelOption;
21  import io.netty.channel.ChannelOutboundBuffer;
22  import io.netty.util.internal.SocketUtils;
23  import io.netty.channel.nio.AbstractNioMessageChannel;
24  import io.netty.channel.socket.DefaultServerSocketChannelConfig;
25  import io.netty.channel.socket.ServerSocketChannelConfig;
26  import io.netty.util.internal.PlatformDependent;
27  import io.netty.util.internal.SuppressJava6Requirement;
28  import io.netty.util.internal.logging.InternalLogger;
29  import io.netty.util.internal.logging.InternalLoggerFactory;
30  
31  import java.io.IOException;
32  import java.net.InetSocketAddress;
33  import java.net.ServerSocket;
34  import java.net.SocketAddress;
35  import java.nio.channels.SelectionKey;
36  import java.nio.channels.ServerSocketChannel;
37  import java.nio.channels.SocketChannel;
38  import java.nio.channels.spi.SelectorProvider;
39  import java.util.List;
40  import java.util.Map;
41  
42  /**
43   * A {@link io.netty.channel.socket.ServerSocketChannel} implementation which uses
44   * NIO selector based implementation to accept new connections.
45   */
46  public class NioServerSocketChannel extends AbstractNioMessageChannel
47                               implements io.netty.channel.socket.ServerSocketChannel {
48  
49      private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
50      private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
51  
52      private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class);
53  
54      private static ServerSocketChannel newSocket(SelectorProvider provider) {
55          try {
56              /**
57               *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
58               *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
59               *
60               *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
61               */
62              return provider.openServerSocketChannel();
63          } catch (IOException e) {
64              throw new ChannelException(
65                      "Failed to open a server socket.", e);
66          }
67      }
68  
69      private final ServerSocketChannelConfig config;
70  
71      /**
72       * Create a new instance
73       */
74      public NioServerSocketChannel() {
75          this(newSocket(DEFAULT_SELECTOR_PROVIDER));
76      }
77  
78      /**
79       * Create a new instance using the given {@link SelectorProvider}.
80       */
81      public NioServerSocketChannel(SelectorProvider provider) {
82          this(newSocket(provider));
83      }
84  
85      /**
86       * Create a new instance using the given {@link ServerSocketChannel}.
87       */
88      public NioServerSocketChannel(ServerSocketChannel channel) {
89          super(null, channel, SelectionKey.OP_ACCEPT);
90          config = new NioServerSocketChannelConfig(this, javaChannel().socket());
91      }
92  
93      @Override
94      public InetSocketAddress localAddress() {
95          return (InetSocketAddress) super.localAddress();
96      }
97  
98      @Override
99      public ChannelMetadata metadata() {
100         return METADATA;
101     }
102 
103     @Override
104     public ServerSocketChannelConfig config() {
105         return config;
106     }
107 
108     @Override
109     public boolean isActive() {
110         // As java.nio.ServerSocketChannel.isBound() will continue to return true even after the channel was closed
111         // we will also need to check if it is open.
112         return isOpen() && javaChannel().socket().isBound();
113     }
114 
115     @Override
116     public InetSocketAddress remoteAddress() {
117         return null;
118     }
119 
120     @Override
121     protected ServerSocketChannel javaChannel() {
122         return (ServerSocketChannel) super.javaChannel();
123     }
124 
125     @Override
126     protected SocketAddress localAddress0() {
127         return SocketUtils.localSocketAddress(javaChannel().socket());
128     }
129 
130     @SuppressJava6Requirement(reason = "Usage guarded by java version check")
131     @Override
132     protected void doBind(SocketAddress localAddress) throws Exception {
133         if (PlatformDependent.javaVersion() >= 7) {
134             javaChannel().bind(localAddress, config.getBacklog());
135         } else {
136             javaChannel().socket().bind(localAddress, config.getBacklog());
137         }
138     }
139 
140     @Override
141     protected void doClose() throws Exception {
142         javaChannel().close();
143     }
144 
145     @Override
146     protected int doReadMessages(List<Object> buf) throws Exception {
147         SocketChannel ch = SocketUtils.accept(javaChannel());
148 
149         try {
150             if (ch != null) {
151                 buf.add(new NioSocketChannel(this, ch));
152                 return 1;
153             }
154         } catch (Throwable t) {
155             logger.warn("Failed to create a new channel from an accepted socket.", t);
156 
157             try {
158                 ch.close();
159             } catch (Throwable t2) {
160                 logger.warn("Failed to close a socket.", t2);
161             }
162         }
163 
164         return 0;
165     }
166 
167     // Unnecessary stuff
168     @Override
169     protected boolean doConnect(
170             SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
171         throw new UnsupportedOperationException();
172     }
173 
174     @Override
175     protected void doFinishConnect() throws Exception {
176         throw new UnsupportedOperationException();
177     }
178 
179     @Override
180     protected SocketAddress remoteAddress0() {
181         return null;
182     }
183 
184     @Override
185     protected void doDisconnect() throws Exception {
186         throw new UnsupportedOperationException();
187     }
188 
189     @Override
190     protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception {
191         throw new UnsupportedOperationException();
192     }
193 
194     @Override
195     protected final Object filterOutboundMessage(Object msg) throws Exception {
196         throw new UnsupportedOperationException();
197     }
198 
199     private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig {
200         private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) {
201             super(channel, javaSocket);
202         }
203 
204         @Override
205         protected void autoReadCleared() {
206             clearReadPending();
207         }
208 
209         @Override
210         public <T> boolean setOption(ChannelOption<T> option, T value) {
211             if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) {
212                 return NioChannelOption.setOption(jdkChannel(), (NioChannelOption<T>) option, value);
213             }
214             return super.setOption(option, value);
215         }
216 
217         @Override
218         public <T> T getOption(ChannelOption<T> option) {
219             if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) {
220                 return NioChannelOption.getOption(jdkChannel(), (NioChannelOption<T>) option);
221             }
222             return super.getOption(option);
223         }
224 
225         @Override
226         public Map<ChannelOption<?>, Object> getOptions() {
227             if (PlatformDependent.javaVersion() >= 7) {
228                 return getOptions(super.getOptions(), NioChannelOption.getOptions(jdkChannel()));
229             }
230             return super.getOptions();
231         }
232 
233         private ServerSocketChannel jdkChannel() {
234             return ((NioServerSocketChannel) channel).javaChannel();
235         }
236     }
237 
238     // Override just to to be able to call directly via unit tests.
239     @Override
240     protected boolean closeOnReadError(Throwable cause) {
241         return super.closeOnReadError(cause);
242     }
243 }