Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/sample/nio/chatserver/ChatServer.java
38829 views
/*1* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940import java.io.IOException;41import java.net.InetSocketAddress;42import java.net.SocketAddress;43import java.net.StandardSocketOptions;44import java.nio.channels.*;45import java.util.*;46import java.util.concurrent.Executors;47import java.util.concurrent.TimeUnit;4849/**50* Implements a chat server, this class holds the list of {@code clients} connected to the server.51* It sets up a server socket using AsynchronousServerSocketChannel listening to a specified port.52*/53public class ChatServer implements Runnable {54private final List<Client> connections = Collections.synchronizedList(new ArrayList<Client>());55private int port;56private final AsynchronousServerSocketChannel listener;57private final AsynchronousChannelGroup channelGroup;5859/**60*61* @param port to listen to62* @throws java.io.IOException when failing to start the server63*/64public ChatServer(int port) throws IOException {65channelGroup = AsynchronousChannelGroup.withFixedThreadPool(Runtime.getRuntime().availableProcessors(),66Executors.defaultThreadFactory());67this.port = port;68listener = createListener(channelGroup);69}7071/**72*73* @return The socket address that the server is bound to74* @throws java.io.IOException if an I/O error occurs75*/76public SocketAddress getSocketAddress() throws IOException {77return listener.getLocalAddress();78}7980/**81* Start accepting connections82*/83public void run() {8485// call accept to wait for connections, tell it to call our CompletionHandler when there86// is a new incoming connection87listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {88@Override89public void completed(AsynchronousSocketChannel result, Void attachment) {90// request a new accept and handle the incoming connection91listener.accept(null, this);92handleNewConnection(result);93}9495@Override96public void failed(Throwable exc, Void attachment) {97}98});99}100101/**102* Shuts down the server103* @throws InterruptedException if terminated while waiting for shutdown104* @throws IOException if failing to shutdown the channel group105*/106public void shutdown() throws InterruptedException, IOException {107channelGroup.shutdownNow();108channelGroup.awaitTermination(1, TimeUnit.SECONDS);109}110111/*112* Creates a listener and starts accepting connections113*/114private AsynchronousServerSocketChannel createListener(AsynchronousChannelGroup channelGroup) throws IOException {115final AsynchronousServerSocketChannel listener = openChannel(channelGroup);116listener.setOption(StandardSocketOptions.SO_REUSEADDR, true);117listener.bind(new InetSocketAddress(port));118return listener;119}120121private AsynchronousServerSocketChannel openChannel(AsynchronousChannelGroup channelGroup) throws IOException {122return AsynchronousServerSocketChannel.open(channelGroup);123}124125/**126* Creates a new client and adds it to the list of connections.127* Sets the clients handler to the initial state of NameReader128*129* @param channel the newly accepted channel130*/131private void handleNewConnection(AsynchronousSocketChannel channel) {132Client client = new Client(channel, new ClientReader(this, new NameReader(this)));133try {134channel.setOption(StandardSocketOptions.TCP_NODELAY, true);135} catch (IOException e) {136// ignore137}138connections.add(client);139client.run();140}141142/**143* Sends a message to all clients except the source.144* The method is synchronized as it is desired that messages are sent to145* all clients in the same order as received.146*147* @param client the message source148* @param message the message to be sent149*/150public void writeMessageToClients(Client client, String message) {151synchronized (connections) {152for (Client clientConnection : connections) {153if (clientConnection != client) {154clientConnection.writeMessageFrom(client, message);155}156}157}158}159160public void removeClient(Client client) {161connections.remove(client);162}163164private static void usage() {165System.err.println("ChatServer [-port <port number>]");166System.exit(1);167}168169public static void main(String[] args) throws IOException {170int port = 5000;171if (args.length != 0 && args.length != 2) {172usage();173} else if (args.length == 2) {174try {175if (args[0].equals("-port")) {176port = Integer.parseInt(args[1]);177} else {178usage();179}180} catch (NumberFormatException e) {181usage();182}183}184System.out.println("Running on port " + port);185new ChatServer(port).run();186}187}188189190