ServerSocket.java revision a3b57e9cb41fb00ac607cd330fa73270b564b66c
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21import java.nio.channels.ServerSocketChannel; 22 23/** 24 * This class represents a server-side socket that waits for incoming client 25 * connections. A {@code ServerSocket} handles the requests and sends back an 26 * appropriate reply. The actual tasks that a server socket must accomplish are 27 * implemented by an internal {@code SocketImpl} instance. 28 */ 29public class ServerSocket { 30 /** 31 * The RI specifies that where the caller doesn't give an explicit backlog, 32 * the default is 50. The OS disagrees, so we need to explicitly call listen(2). 33 */ 34 private static final int DEFAULT_BACKLOG = 50; 35 36 private final SocketImpl impl; 37 38 /** 39 * @hide internal use only 40 */ 41 public SocketImpl getImpl$() { 42 return impl; 43 } 44 45 static SocketImplFactory factory; 46 47 private boolean isBound; 48 49 private boolean isClosed; 50 51 /** 52 * Constructs a new unbound {@code ServerSocket}. 53 * 54 * @throws IOException if an error occurs while creating the socket. 55 */ 56 public ServerSocket() throws IOException { 57 this.impl = factory != null ? factory.createSocketImpl() 58 : new PlainServerSocketImpl(); 59 impl.create(true); 60 } 61 62 /** 63 * Constructs a new {@code ServerSocket} instance bound to the given {@code port}. 64 * The backlog is set to 50. If {@code port == 0}, a port will be assigned by the OS. 65 * 66 * @throws IOException if an error occurs while creating the socket. 67 */ 68 public ServerSocket(int port) throws IOException { 69 this(port, DEFAULT_BACKLOG, Inet4Address.ANY); 70 } 71 72 /** 73 * Constructs a new {@code ServerSocket} instance bound to the given {@code port}. 74 * The backlog is set to {@code backlog}. 75 * If {@code port == 0}, a port will be assigned by the OS. 76 * 77 * @throws IOException if an error occurs while creating the socket. 78 */ 79 public ServerSocket(int port, int backlog) throws IOException { 80 this(port, backlog, Inet4Address.ANY); 81 } 82 83 /** 84 * Constructs a new {@code ServerSocket} instance bound to the given {@code localAddress} 85 * and {@code port}. The backlog is set to {@code backlog}. 86 * If {@code localAddress == null}, the ANY address is used. 87 * If {@code port == 0}, a port will be assigned by the OS. 88 * 89 * @throws IOException if an error occurs while creating the socket. 90 */ 91 public ServerSocket(int port, int backlog, InetAddress localAddress) throws IOException { 92 checkListen(port); 93 this.impl = factory != null ? factory.createSocketImpl() 94 : new PlainServerSocketImpl(); 95 InetAddress addr = (localAddress == null) ? Inet4Address.ANY : localAddress; 96 97 synchronized (this) { 98 impl.create(true); 99 try { 100 impl.bind(addr, port); 101 isBound = true; 102 impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG); 103 } catch (IOException e) { 104 close(); 105 throw e; 106 } 107 } 108 } 109 110 /** 111 * Waits for an incoming request and blocks until the connection is opened. 112 * This method returns a socket object representing the just opened 113 * connection. 114 * 115 * @return the connection representing socket. 116 * @throws IOException 117 * if an error occurs while accepting a new connection. 118 */ 119 public Socket accept() throws IOException { 120 checkOpen(); 121 if (!isBound()) { 122 throw new SocketException("Socket is not bound"); 123 } 124 125 Socket aSocket = new Socket(); 126 try { 127 implAccept(aSocket); 128 } catch (IOException e) { 129 aSocket.close(); 130 throw e; 131 } 132 return aSocket; 133 } 134 135 private void checkListen(int aPort) { 136 if (aPort < 0 || aPort > 65535) { 137 throw new IllegalArgumentException("Port out of range: " + aPort); 138 } 139 } 140 141 /** 142 * Closes this server socket and its implementation. Any attempt to connect 143 * to this socket thereafter will fail. 144 * 145 * @throws IOException 146 * if an error occurs while closing this socket. 147 */ 148 public void close() throws IOException { 149 isClosed = true; 150 impl.close(); 151 } 152 153 /** 154 * Gets the local IP address of this server socket or {@code null} if the 155 * socket is unbound. This is useful for multihomed hosts. 156 * 157 * @return the local address of this server socket. 158 */ 159 public InetAddress getInetAddress() { 160 if (!isBound()) { 161 return null; 162 } 163 return impl.getInetAddress(); 164 } 165 166 /** 167 * Gets the local port of this server socket or {@code -1} if the socket is 168 * unbound. 169 * 170 * @return the local port this server is listening on. 171 */ 172 public int getLocalPort() { 173 if (!isBound()) { 174 return -1; 175 } 176 return impl.getLocalPort(); 177 } 178 179 /** 180 * Gets the socket {@link SocketOptions#SO_TIMEOUT accept timeout}. 181 * 182 * @throws IOException 183 * if the option cannot be retrieved. 184 */ 185 public synchronized int getSoTimeout() throws IOException { 186 checkOpen(); 187 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 188 } 189 190 /** 191 * Invokes the server socket implementation to accept a connection on the 192 * given socket {@code aSocket}. 193 * 194 * @param aSocket 195 * the concrete {@code SocketImpl} to accept the connection 196 * request on. 197 * @throws IOException 198 * if the connection cannot be accepted. 199 */ 200 protected final void implAccept(Socket aSocket) throws IOException { 201 synchronized (this) { 202 impl.accept(aSocket.impl); 203 aSocket.accepted(); 204 } 205 } 206 207 /** 208 * Sets the server socket implementation factory of this instance. This 209 * method may only be invoked with sufficient security privilege and only 210 * once during the application lifetime. 211 * 212 * @param aFactory 213 * the streaming socket factory to be used for further socket 214 * instantiations. 215 * @throws IOException 216 * if the factory could not be set or is already set. 217 */ 218 public static synchronized void setSocketFactory(SocketImplFactory aFactory) throws IOException { 219 if (factory != null) { 220 throw new SocketException("Factory already set"); 221 } 222 factory = aFactory; 223 } 224 225 /** 226 * Sets the {@link SocketOptions#SO_TIMEOUT accept timeout} in milliseconds for this socket. 227 * This accept timeout defines the period the socket will block waiting to 228 * accept a connection before throwing an {@code InterruptedIOException}. The value 229 * {@code 0} (default) is used to set an infinite timeout. To have effect 230 * this option must be set before the blocking method was called. 231 * 232 * @param timeout the timeout in milliseconds or 0 for no timeout. 233 * @throws SocketException 234 * if an error occurs while setting the option. 235 */ 236 public synchronized void setSoTimeout(int timeout) throws SocketException { 237 checkOpen(); 238 if (timeout < 0) { 239 throw new IllegalArgumentException("timeout < 0"); 240 } 241 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 242 } 243 244 /** 245 * Returns a textual representation of this server socket including the 246 * address, port and the state. The port field is set to {@code 0} if there 247 * is no connection to the server socket. 248 * 249 * @return the textual socket representation. 250 */ 251 @Override 252 public String toString() { 253 StringBuilder result = new StringBuilder(64); 254 result.append("ServerSocket["); 255 if (!isBound()) { 256 return result.append("unbound]").toString(); 257 } 258 return result.append("addr=") 259 .append(getInetAddress().getHostName()).append("/") 260 .append(getInetAddress().getHostAddress()).append( 261 ",port=0,localport=") 262 .append(getLocalPort()).append("]") 263 .toString(); 264 } 265 266 /** 267 * Binds this server socket to the given local socket address with a maximum 268 * backlog of 50 unaccepted connections. If the {@code localAddr} is set to 269 * {@code null} the socket will be bound to an available local address on 270 * any free port of the system. 271 * 272 * @param localAddr 273 * the local address and port to bind on. 274 * @throws IllegalArgumentException 275 * if the {@code SocketAddress} is not supported. 276 * @throws IOException 277 * if the socket is already bound or a problem occurs during 278 * binding. 279 */ 280 public void bind(SocketAddress localAddr) throws IOException { 281 bind(localAddr, DEFAULT_BACKLOG); 282 } 283 284 /** 285 * Binds this server socket to the given local socket address. If the 286 * {@code localAddr} is set to {@code null} the socket will be bound to an 287 * available local address on any free port of the system. 288 * 289 * @param localAddr the local machine address and port to bind on. 290 * @param backlog the maximum number of unaccepted connections. Passing 0 or 291 * a negative value yields the default backlog of 50. 292 * @throws IllegalArgumentException if the {@code SocketAddress} is not 293 * supported. 294 * @throws IOException if the socket is already bound or a problem occurs 295 * during binding. 296 */ 297 public void bind(SocketAddress localAddr, int backlog) throws IOException { 298 checkOpen(); 299 if (isBound()) { 300 throw new BindException("Socket is already bound"); 301 } 302 int port = 0; 303 InetAddress addr = Inet4Address.ANY; 304 if (localAddr != null) { 305 if (!(localAddr instanceof InetSocketAddress)) { 306 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 307 localAddr.getClass()); 308 } 309 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 310 if ((addr = inetAddr.getAddress()) == null) { 311 throw new SocketException("Host is unresolved: " + inetAddr.getHostName()); 312 } 313 port = inetAddr.getPort(); 314 } 315 316 synchronized (this) { 317 try { 318 impl.bind(addr, port); 319 isBound = true; 320 impl.listen(backlog > 0 ? backlog : DEFAULT_BACKLOG); 321 } catch (IOException e) { 322 close(); 323 throw e; 324 } 325 } 326 } 327 328 /** 329 * Gets the local socket address of this server socket or {@code null} if 330 * the socket is unbound. This is useful on multihomed hosts. 331 * 332 * @return the local socket address and port this socket is bound to. 333 */ 334 public SocketAddress getLocalSocketAddress() { 335 if (!isBound()) { 336 return null; 337 } 338 return new InetSocketAddress(getInetAddress(), getLocalPort()); 339 } 340 341 /** 342 * Returns whether this server socket is bound to a local address and port 343 * or not. 344 * 345 * @return {@code true} if this socket is bound, {@code false} otherwise. 346 */ 347 public boolean isBound() { 348 return isBound; 349 } 350 351 /** 352 * Returns whether this server socket is closed or not. 353 * 354 * @return {@code true} if this socket is closed, {@code false} otherwise. 355 */ 356 public boolean isClosed() { 357 return isClosed; 358 } 359 360 private void checkOpen() throws SocketException { 361 if (isClosed()) { 362 throw new SocketException("Socket is closed"); 363 } 364 } 365 366 /** 367 * Sets the value for the socket option {@code SocketOptions.SO_REUSEADDR}. 368 * 369 * @param reuse 370 * the socket option setting. 371 * @throws SocketException 372 * if an error occurs while setting the option value. 373 */ 374 public void setReuseAddress(boolean reuse) throws SocketException { 375 checkOpen(); 376 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse)); 377 } 378 379 /** 380 * Gets the value of the socket option {@code SocketOptions.SO_REUSEADDR}. 381 * 382 * @return {@code true} if the option is enabled, {@code false} otherwise. 383 * @throws SocketException 384 * if an error occurs while reading the option value. 385 */ 386 public boolean getReuseAddress() throws SocketException { 387 checkOpen(); 388 return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)).booleanValue(); 389 } 390 391 /** 392 * Sets this socket's {@link SocketOptions#SO_SNDBUF receive buffer size}. 393 */ 394 public void setReceiveBufferSize(int size) throws SocketException { 395 checkOpen(); 396 if (size < 1) { 397 throw new IllegalArgumentException("size < 1"); 398 } 399 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 400 } 401 402 /** 403 * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}. 404 */ 405 public int getReceiveBufferSize() throws SocketException { 406 checkOpen(); 407 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 408 } 409 410 /** 411 * Returns this socket's {@code ServerSocketChannel}, if one exists. A channel is 412 * available only if this socket wraps a channel. (That is, you can go from a 413 * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.) 414 * In practice, this means that the socket must have been created by 415 * {@link java.nio.channels.ServerSocketChannel#open}. 416 */ 417 public ServerSocketChannel getChannel() { 418 return null; 419 } 420 421 /** 422 * Sets performance preferences for connection time, latency and bandwidth. 423 * <p> 424 * This method does currently nothing. 425 * 426 * @param connectionTime 427 * the value representing the importance of a short connecting 428 * time. 429 * @param latency 430 * the value representing the importance of low latency. 431 * @param bandwidth 432 * the value representing the importance of high bandwidth. 433 */ 434 public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { 435 // Our socket implementation only provide one protocol: TCP/IP, so 436 // we do nothing for this method 437 } 438} 439