Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/sample/nio/chatserver/ChatServer.java
38829 views
1
/*
2
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
*
8
* - Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
*
11
* - Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* - Neither the name of Oracle nor the names of its
16
* contributors may be used to endorse or promote products derived
17
* from this software without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
*/
31
32
/*
33
* This source code is provided to illustrate the usage of a given feature
34
* or technique and has been deliberately simplified. Additional steps
35
* required for a production-quality application, such as security checks,
36
* input validation and proper error handling, might not be present in
37
* this sample code.
38
*/
39
40
41
import java.io.IOException;
42
import java.net.InetSocketAddress;
43
import java.net.SocketAddress;
44
import java.net.StandardSocketOptions;
45
import java.nio.channels.*;
46
import java.util.*;
47
import java.util.concurrent.Executors;
48
import java.util.concurrent.TimeUnit;
49
50
/**
51
* Implements a chat server, this class holds the list of {@code clients} connected to the server.
52
* It sets up a server socket using AsynchronousServerSocketChannel listening to a specified port.
53
*/
54
public class ChatServer implements Runnable {
55
private final List<Client> connections = Collections.synchronizedList(new ArrayList<Client>());
56
private int port;
57
private final AsynchronousServerSocketChannel listener;
58
private final AsynchronousChannelGroup channelGroup;
59
60
/**
61
*
62
* @param port to listen to
63
* @throws java.io.IOException when failing to start the server
64
*/
65
public ChatServer(int port) throws IOException {
66
channelGroup = AsynchronousChannelGroup.withFixedThreadPool(Runtime.getRuntime().availableProcessors(),
67
Executors.defaultThreadFactory());
68
this.port = port;
69
listener = createListener(channelGroup);
70
}
71
72
/**
73
*
74
* @return The socket address that the server is bound to
75
* @throws java.io.IOException if an I/O error occurs
76
*/
77
public SocketAddress getSocketAddress() throws IOException {
78
return listener.getLocalAddress();
79
}
80
81
/**
82
* Start accepting connections
83
*/
84
public void run() {
85
86
// call accept to wait for connections, tell it to call our CompletionHandler when there
87
// is a new incoming connection
88
listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
89
@Override
90
public void completed(AsynchronousSocketChannel result, Void attachment) {
91
// request a new accept and handle the incoming connection
92
listener.accept(null, this);
93
handleNewConnection(result);
94
}
95
96
@Override
97
public void failed(Throwable exc, Void attachment) {
98
}
99
});
100
}
101
102
/**
103
* Shuts down the server
104
* @throws InterruptedException if terminated while waiting for shutdown
105
* @throws IOException if failing to shutdown the channel group
106
*/
107
public void shutdown() throws InterruptedException, IOException {
108
channelGroup.shutdownNow();
109
channelGroup.awaitTermination(1, TimeUnit.SECONDS);
110
}
111
112
/*
113
* Creates a listener and starts accepting connections
114
*/
115
private AsynchronousServerSocketChannel createListener(AsynchronousChannelGroup channelGroup) throws IOException {
116
final AsynchronousServerSocketChannel listener = openChannel(channelGroup);
117
listener.setOption(StandardSocketOptions.SO_REUSEADDR, true);
118
listener.bind(new InetSocketAddress(port));
119
return listener;
120
}
121
122
private AsynchronousServerSocketChannel openChannel(AsynchronousChannelGroup channelGroup) throws IOException {
123
return AsynchronousServerSocketChannel.open(channelGroup);
124
}
125
126
/**
127
* Creates a new client and adds it to the list of connections.
128
* Sets the clients handler to the initial state of NameReader
129
*
130
* @param channel the newly accepted channel
131
*/
132
private void handleNewConnection(AsynchronousSocketChannel channel) {
133
Client client = new Client(channel, new ClientReader(this, new NameReader(this)));
134
try {
135
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
136
} catch (IOException e) {
137
// ignore
138
}
139
connections.add(client);
140
client.run();
141
}
142
143
/**
144
* Sends a message to all clients except the source.
145
* The method is synchronized as it is desired that messages are sent to
146
* all clients in the same order as received.
147
*
148
* @param client the message source
149
* @param message the message to be sent
150
*/
151
public void writeMessageToClients(Client client, String message) {
152
synchronized (connections) {
153
for (Client clientConnection : connections) {
154
if (clientConnection != client) {
155
clientConnection.writeMessageFrom(client, message);
156
}
157
}
158
}
159
}
160
161
public void removeClient(Client client) {
162
connections.remove(client);
163
}
164
165
private static void usage() {
166
System.err.println("ChatServer [-port <port number>]");
167
System.exit(1);
168
}
169
170
public static void main(String[] args) throws IOException {
171
int port = 5000;
172
if (args.length != 0 && args.length != 2) {
173
usage();
174
} else if (args.length == 2) {
175
try {
176
if (args[0].equals("-port")) {
177
port = Integer.parseInt(args[1]);
178
} else {
179
usage();
180
}
181
} catch (NumberFormatException e) {
182
usage();
183
}
184
}
185
System.out.println("Running on port " + port);
186
new ChatServer(port).run();
187
}
188
}
189
190