ServerSocket.java revision 32c2297a959b72abdb18743f0519e1d8b7c7ea88
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 SocketImpl impl; 32 33 static SocketImplFactory factory; 34 35 private volatile boolean isCreated; 36 37 private boolean isBound; 38 39 private boolean isClosed; 40 41 /** 42 * Constructs a new {@code ServerSocket} instance which is not bound to any 43 * port. The default number of pending connections may be backlogged. 44 * 45 * @throws IOException 46 * if an error occurs while creating the server socket. 47 */ 48 public ServerSocket() throws IOException { 49 impl = factory != null ? factory.createSocketImpl() 50 : new PlainServerSocketImpl(); 51 } 52 53 /** 54 * Unspecified constructor needed by ServerSocketChannelImpl.ServerSocketAdapter. 55 * 56 * @hide 57 */ 58 protected ServerSocket(SocketImpl impl) { 59 this.impl = impl; 60 } 61 62 /** 63 * Constructs a new {@code ServerSocket} instance bound to the nominated 64 * port on the localhost. The default number of pending connections may be 65 * backlogged. If {@code aport} is 0 a free port is assigned to the socket. 66 * 67 * @param aport 68 * the port number to listen for connection requests on. 69 * @throws IOException 70 * if an error occurs while creating the server socket. 71 */ 72 public ServerSocket(int aport) throws IOException { 73 this(aport, defaultBacklog(), Inet4Address.ANY); 74 } 75 76 /** 77 * Constructs a new {@code ServerSocket} instance bound to the nominated 78 * port on the localhost. The number of pending connections that may be 79 * backlogged is specified by {@code backlog}. If {@code aport} is 0 a free 80 * port is assigned to the socket. 81 * 82 * @param aport 83 * the port number to listen for connection requests on. 84 * @param backlog 85 * the number of pending connection requests, before requests 86 * will be rejected. 87 * @throws IOException 88 * if an error occurs while creating the server socket. 89 */ 90 public ServerSocket(int aport, int backlog) throws IOException { 91 this(aport, backlog, Inet4Address.ANY); 92 } 93 94 /** 95 * Constructs a new {@code ServerSocket} instance bound to the nominated 96 * local host address and port. The number of pending connections that may 97 * be backlogged is specified by {@code backlog}. If {@code aport} is 0 a 98 * free port is assigned to the socket. 99 * 100 * @param aport 101 * the port number to listen for connection requests on. 102 * @param localAddr 103 * the local machine address to bind on. 104 * @param backlog 105 * the number of pending connection requests, before requests 106 * will be rejected. 107 * @throws IOException 108 * if an error occurs while creating the server socket. 109 */ 110 public ServerSocket(int aport, int backlog, InetAddress localAddr) throws IOException { 111 checkListen(aport); 112 impl = factory != null ? factory.createSocketImpl() 113 : new PlainServerSocketImpl(); 114 InetAddress addr = localAddr == null ? Inet4Address.ANY : localAddr; 115 116 synchronized (this) { 117 impl.create(true); 118 isCreated = true; 119 try { 120 impl.bind(addr, aport); 121 isBound = true; 122 impl.listen(backlog > 0 ? backlog : defaultBacklog()); 123 } catch (IOException e) { 124 close(); 125 throw e; 126 } 127 } 128 } 129 130 /** 131 * Waits for an incoming request and blocks until the connection is opened. 132 * This method returns a socket object representing the just opened 133 * connection. 134 * 135 * @return the connection representing socket. 136 * @throws IOException 137 * if an error occurs while accepting a new connection. 138 */ 139 public Socket accept() throws IOException { 140 checkClosedAndCreate(false); 141 if (!isBound()) { 142 throw new SocketException("Socket is not bound"); 143 } 144 145 Socket aSocket = new Socket(); 146 try { 147 implAccept(aSocket); 148 } catch (IOException e) { 149 aSocket.close(); 150 throw e; 151 } 152 return aSocket; 153 } 154 155 private void checkListen(int aPort) { 156 if (aPort < 0 || aPort > 65535) { 157 throw new IllegalArgumentException("Port out of range: " + aPort); 158 } 159 } 160 161 /** 162 * Closes this server socket and its implementation. Any attempt to connect 163 * to this socket thereafter will fail. 164 * 165 * @throws IOException 166 * if an error occurs while closing this socket. 167 */ 168 public void close() throws IOException { 169 isClosed = true; 170 impl.close(); 171 } 172 173 /** 174 * Returns the default number of pending connections on a server socket. If 175 * the backlog value maximum is reached, any subsequent incoming request is 176 * rejected. 177 * 178 * @return int the default number of pending connection requests 179 */ 180 static int defaultBacklog() { 181 return 50; 182 } 183 184 /** 185 * Gets the local IP address of this server socket or {@code null} if the 186 * socket is unbound. This is useful for multihomed hosts. 187 * 188 * @return the local address of this server socket. 189 */ 190 public InetAddress getInetAddress() { 191 if (!isBound()) { 192 return null; 193 } 194 return impl.getInetAddress(); 195 } 196 197 /** 198 * Gets the local port of this server socket or {@code -1} if the socket is 199 * unbound. 200 * 201 * @return the local port this server is listening on. 202 */ 203 public int getLocalPort() { 204 if (!isBound()) { 205 return -1; 206 } 207 return impl.getLocalPort(); 208 } 209 210 /** 211 * Gets the socket {@link SocketOptions#SO_TIMEOUT accept timeout}. 212 * 213 * @throws IOException 214 * if the option cannot be retrieved. 215 */ 216 public synchronized int getSoTimeout() throws IOException { 217 if (!isCreated) { 218 synchronized (this) { 219 if (!isCreated) { 220 try { 221 impl.create(true); 222 } catch (SocketException e) { 223 throw e; 224 } catch (IOException e) { 225 throw new SocketException(e.toString()); 226 } 227 isCreated = true; 228 } 229 } 230 } 231 return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); 232 } 233 234 /** 235 * Invokes the server socket implementation to accept a connection on the 236 * given socket {@code aSocket}. 237 * 238 * @param aSocket 239 * the concrete {@code SocketImpl} to accept the connection 240 * request on. 241 * @throws IOException 242 * if the connection cannot be accepted. 243 */ 244 protected final void implAccept(Socket aSocket) throws IOException { 245 synchronized (this) { 246 impl.accept(aSocket.impl); 247 aSocket.accepted(); 248 } 249 } 250 251 /** 252 * Sets the server socket implementation factory of this instance. This 253 * method may only be invoked with sufficient security privilege and only 254 * once during the application lifetime. 255 * 256 * @param aFactory 257 * the streaming socket factory to be used for further socket 258 * instantiations. 259 * @throws IOException 260 * if the factory could not be set or is already set. 261 */ 262 public static synchronized void setSocketFactory(SocketImplFactory aFactory) 263 throws IOException { 264 if (factory != null) { 265 throw new SocketException("Factory already set"); 266 } 267 factory = aFactory; 268 } 269 270 /** 271 * Sets the {@link SocketOptions#SO_TIMEOUT accept timeout} in milliseconds for this socket. 272 * This accept timeout defines the period the socket will block waiting to 273 * accept a connection before throwing an {@code InterruptedIOException}. The value 274 * {@code 0} (default) is used to set an infinite timeout. To have effect 275 * this option must be set before the blocking method was called. 276 * 277 * @param timeout the timeout in milliseconds or 0 for no timeout. 278 * @throws SocketException 279 * if an error occurs while setting the option. 280 */ 281 public synchronized void setSoTimeout(int timeout) throws SocketException { 282 checkClosedAndCreate(true); 283 if (timeout < 0) { 284 throw new IllegalArgumentException("timeout < 0"); 285 } 286 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 287 } 288 289 /** 290 * Returns a textual representation of this server socket including the 291 * address, port and the state. The port field is set to {@code 0} if there 292 * is no connection to the server socket. 293 * 294 * @return the textual socket representation. 295 */ 296 @Override 297 public String toString() { 298 StringBuilder result = new StringBuilder(64); 299 result.append("ServerSocket["); 300 if (!isBound()) { 301 return result.append("unbound]").toString(); 302 } 303 return result.append("addr=") 304 .append(getInetAddress().getHostName()).append("/") 305 .append(getInetAddress().getHostAddress()).append( 306 ",port=0,localport=") 307 .append(getLocalPort()).append("]") 308 .toString(); 309 } 310 311 /** 312 * Binds this server socket to the given local socket address with a maximum 313 * backlog of 50 unaccepted connections. If the {@code localAddr} is set to 314 * {@code null} the socket will be bound to an available local address on 315 * any free port of the system. 316 * 317 * @param localAddr 318 * the local address and port to bind on. 319 * @throws IllegalArgumentException 320 * if the {@code SocketAddress} is not supported. 321 * @throws IOException 322 * if the socket is already bound or a problem occurs during 323 * binding. 324 */ 325 public void bind(SocketAddress localAddr) throws IOException { 326 bind(localAddr, defaultBacklog()); 327 } 328 329 /** 330 * Binds this server socket to the given local socket address. If the 331 * {@code localAddr} is set to {@code null} the socket will be bound to an 332 * available local address on any free port of the system. 333 * 334 * @param localAddr the local machine address and port to bind on. 335 * @param backlog the maximum number of unaccepted connections. Passing 0 or 336 * a negative value yields the default backlog of 50. 337 * @throws IllegalArgumentException if the {@code SocketAddress} is not 338 * supported. 339 * @throws IOException if the socket is already bound or a problem occurs 340 * during binding. 341 */ 342 public void bind(SocketAddress localAddr, int backlog) throws IOException { 343 checkClosedAndCreate(true); 344 if (isBound()) { 345 throw new BindException("Socket is already bound"); 346 } 347 int port = 0; 348 InetAddress addr = Inet4Address.ANY; 349 if (localAddr != null) { 350 if (!(localAddr instanceof InetSocketAddress)) { 351 throw new IllegalArgumentException("Local address not an InetSocketAddress: " + 352 localAddr.getClass()); 353 } 354 InetSocketAddress inetAddr = (InetSocketAddress) localAddr; 355 if ((addr = inetAddr.getAddress()) == null) { 356 throw new SocketException("Host is unresolved: " + inetAddr.getHostName()); 357 } 358 port = inetAddr.getPort(); 359 } 360 361 synchronized (this) { 362 try { 363 impl.bind(addr, port); 364 isBound = true; 365 impl.listen(backlog > 0 ? backlog : defaultBacklog()); 366 } catch (IOException e) { 367 close(); 368 throw e; 369 } 370 } 371 } 372 373 /** 374 * Gets the local socket address of this server socket or {@code null} if 375 * the socket is unbound. This is useful on multihomed hosts. 376 * 377 * @return the local socket address and port this socket is bound to. 378 */ 379 public SocketAddress getLocalSocketAddress() { 380 if (!isBound()) { 381 return null; 382 } 383 return new InetSocketAddress(getInetAddress(), getLocalPort()); 384 } 385 386 /** 387 * Returns whether this server socket is bound to a local address and port 388 * or not. 389 * 390 * @return {@code true} if this socket is bound, {@code false} otherwise. 391 */ 392 public boolean isBound() { 393 return isBound; 394 } 395 396 /** 397 * Returns whether this server socket is closed or not. 398 * 399 * @return {@code true} if this socket is closed, {@code false} otherwise. 400 */ 401 public boolean isClosed() { 402 return isClosed; 403 } 404 405 /** 406 * Checks whether the socket is closed, and throws an exception. 407 */ 408 private void checkClosedAndCreate(boolean create) throws SocketException { 409 if (isClosed()) { 410 throw new SocketException("Socket is closed"); 411 } 412 413 if (!create || isCreated) { 414 return; 415 } 416 417 synchronized (this) { 418 if (isCreated) { 419 return; 420 } 421 try { 422 impl.create(true); 423 } catch (SocketException e) { 424 throw e; 425 } catch (IOException e) { 426 throw new SocketException(e.toString()); 427 } 428 isCreated = true; 429 } 430 } 431 432 /** 433 * Sets the value for the socket option {@code SocketOptions.SO_REUSEADDR}. 434 * 435 * @param reuse 436 * the socket option setting. 437 * @throws SocketException 438 * if an error occurs while setting the option value. 439 */ 440 public void setReuseAddress(boolean reuse) throws SocketException { 441 checkClosedAndCreate(true); 442 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse)); 443 } 444 445 /** 446 * Gets the value of the socket option {@code SocketOptions.SO_REUSEADDR}. 447 * 448 * @return {@code true} if the option is enabled, {@code false} otherwise. 449 * @throws SocketException 450 * if an error occurs while reading the option value. 451 */ 452 public boolean getReuseAddress() throws SocketException { 453 checkClosedAndCreate(true); 454 return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR)) 455 .booleanValue(); 456 } 457 458 /** 459 * Sets this socket's {@link SocketOptions#SO_SNDBUF receive buffer size}. 460 */ 461 public void setReceiveBufferSize(int size) throws SocketException { 462 checkClosedAndCreate(true); 463 if (size < 1) { 464 throw new IllegalArgumentException("size < 1"); 465 } 466 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 467 } 468 469 /** 470 * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}. 471 */ 472 public int getReceiveBufferSize() throws SocketException { 473 checkClosedAndCreate(true); 474 return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); 475 } 476 477 /** 478 * Returns this socket's {@code ServerSocketChannel}, if one exists. A channel is 479 * available only if this socket wraps a channel. (That is, you can go from a 480 * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.) 481 * In practice, this means that the socket must have been created by 482 * {@link java.nio.channels.ServerSocketChannel#open}. 483 */ 484 public ServerSocketChannel getChannel() { 485 return null; 486 } 487 488 /** 489 * Sets performance preferences for connection time, latency and bandwidth. 490 * <p> 491 * This method does currently nothing. 492 * 493 * @param connectionTime 494 * the value representing the importance of a short connecting 495 * time. 496 * @param latency 497 * the value representing the importance of low latency. 498 * @param bandwidth 499 * the value representing the importance of high bandwidth. 500 */ 501 public void setPerformancePreferences(int connectionTime, int latency, 502 int bandwidth) { 503 // Our socket implementation only provide one protocol: TCP/IP, so 504 // we do nothing for this method 505 } 506} 507