-
Notifications
You must be signed in to change notification settings - Fork 668
/
InetSocketAddress.java
466 lines (396 loc) · 17.7 KB
/
InetSocketAddress.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.ObjectStreamField;
/**
* This class implements an IP Socket Address (IP address + port number)
* It can also be a pair (hostname + port number), in which case an attempt
* will be made to resolve the hostname. If resolution fails then the address
* is said to be <I>unresolved</I> but can still be used on some circumstances
* like connecting through a proxy.
* <p>
* It provides an immutable object used by sockets for binding, connecting, or
* as returned values.
* <p>
* The <i>wildcard</i> is a special local IP address. It usually means "any"
* and can only be used for {@code bind} operations.
*
* @see java.net.Socket
* @see java.net.ServerSocket
* @since 1.4
*/
// 表示一个基于IP的Socket地址(ip + port),用于TCP/UDP连接
public class InetSocketAddress extends SocketAddress {
private final transient InetSocketAddressHolder holder;
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Creates a socket address where the IP address is the wildcard address
* and the port number a specified value.
* <p>
* A valid port value is between 0 and 65535.
* A port number of {@code zero} will let the system pick up an
* ephemeral port in a {@code bind} operation.
*
* @param port The port number
*
* @throws IllegalArgumentException if the port parameter is outside the specified
* range of valid port values.
*/
// 使用通配IP和指定的端口号初始化Socket地址;端口为0时随机分配端口
public InetSocketAddress(int port) {
this(InetAddress.anyLocalAddress(), port);
}
/**
* Creates a socket address from an IP address and a port number.
* <p>
* A valid port value is between 0 and 65535.
* A port number of {@code zero} will let the system pick up an
* ephemeral port in a {@code bind} operation.
* <P>
* A {@code null} address will assign the <i>wildcard</i> address.
*
* @param addr The IP address
* @param port The port number
*
* @throws IllegalArgumentException if the port parameter is outside the specified
* range of valid port values.
*/
// 使用指定的IP地址和port构造一个Socket地址;如果IP地址为null,使用通配地址;如果端口号为0,则使用随机端口
public InetSocketAddress(InetAddress addr, int port) {
holder = new InetSocketAddressHolder(null, addr == null ? InetAddress.anyLocalAddress() : addr, checkPort(port));
}
/**
* Creates a socket address from a hostname and a port number.
* <p>
* An attempt will be made to resolve the hostname into an InetAddress.
* If that attempt fails, the address will be flagged as <I>unresolved</I>.
* <p>
* If there is a security manager, its {@code checkConnect} method
* is called with the host name as its argument to check the permission
* to resolve it. This could result in a SecurityException.
* <P>
* A valid port value is between 0 and 65535.
* A port number of {@code zero} will let the system pick up an
* ephemeral port in a {@code bind} operation.
*
* @param hostname the Host name
* @param port The port number
*
* @throws IllegalArgumentException if the port parameter is outside the range
* of valid port values, or if the hostname parameter is {@code null}.
* @throws SecurityException if a security manager is present and
* permission to resolve the host name is
* denied.
* @see #isUnresolved()
*/
// 使用指定的主机名称/地址和port初始化Socket地址;端口为0时随机分配端口
public InetSocketAddress(String hostname, int port) {
checkHost(hostname);
InetAddress addr = null;
String host = null;
try {
// 根据主机名称或主机IP,创建/查找其对应的InetAddress实例(有多个实例时只选择第一个)
addr = InetAddress.getByName(hostname);
} catch(UnknownHostException e) {
host = hostname;
}
holder = new InetSocketAddressHolder(host, addr, checkPort(port));
}
/** private constructor for creating unresolved instances */
// 构造一个"未解析"的Socket地址
private InetSocketAddress(int port, String hostname) {
holder = new InetSocketAddressHolder(hostname, null, port);
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 工厂方法 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Creates an unresolved socket address from a hostname and a port number.
* <p>
* No attempt will be made to resolve the hostname into an InetAddress.
* The address will be flagged as <I>unresolved</I>.
* <p>
* A valid port value is between 0 and 65535.
* A port number of {@code zero} will let the system pick up an
* ephemeral port in a {@code bind} operation.
*
* @param host the Host name
* @param port The port number
*
* @return an {@code InetSocketAddress} representing the unresolved
* socket address
*
* @throws IllegalArgumentException if the port parameter is outside
* the range of valid port values, or if the hostname
* parameter is {@code null}.
* @see #isUnresolved()
* @since 1.5
*/
// 创建一个未解析的Socket地址
public static InetSocketAddress createUnresolved(String host, int port) {
return new InetSocketAddress(checkPort(port), checkHost(host));
}
/*▲ 工厂方法 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 属性 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Gets the port number.
*
* @return the port number.
*/
// 获取端口号
public final int getPort() {
return holder.getPort();
}
/**
* Gets the {@code InetAddress}.
*
* @return the InetAddress or {@code null} if it is unresolved.
*/
// 获取IP地址
public final InetAddress getAddress() {
return holder.getAddress();
}
/**
* Gets the {@code hostname}.
* Note: This method may trigger a name service reverse lookup if the
* address was created with a literal IP address.
*
* @return the hostname part of the address.
*/
// 获取主机名称
public final String getHostName() {
return holder.getHostName();
}
/**
* Returns the hostname, or the String form of the address if it
* doesn't have a hostname (it was created using a literal).
* This has the benefit of <b>not</b> attempting a reverse lookup.
*
* @return the hostname, or String representation of the address.
*
* @since 1.7
*/
// 获取主机名称或主机地址
public final String getHostString() {
return holder.getHostString();
}
/**
* Checks whether the address has been resolved or not.
*
* @return {@code true} if the hostname couldn't be resolved into
* an {@code InetAddress}.
*/
// 是否为"未解析"的socket地址
public final boolean isUnresolved() {
return holder.isUnresolved();
}
/*▲ 属性 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 序列化 ████████████████████████████████████████████████████████████████████████████████┓ */
private static final long serialVersionUID = 5076001401234631237L;
private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe();
private static final long FIELDS_OFFSET = UNSAFE.objectFieldOffset(InetSocketAddress.class, "holder");
/**
* @serialField hostname String
* @serialField addr InetAddress
* @serialField port int
*/
private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("hostname", String.class), new ObjectStreamField("addr", InetAddress.class), new ObjectStreamField("port", int.class)};
private void writeObject(ObjectOutputStream out) throws IOException {
// Don't call defaultWriteObject()
ObjectOutputStream.PutField pfields = out.putFields();
pfields.put("hostname", holder.hostname);
pfields.put("addr", holder.addr);
pfields.put("port", holder.port);
out.writeFields();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// Don't call defaultReadObject()
ObjectInputStream.GetField oisFields = in.readFields();
final String oisHostname = (String) oisFields.get("hostname", null);
final InetAddress oisAddr = (InetAddress) oisFields.get("addr", null);
final int oisPort = oisFields.get("port", -1);
// Check that our invariants are satisfied
checkPort(oisPort);
if(oisHostname == null && oisAddr == null)
throw new InvalidObjectException("hostname and addr " + "can't both be null");
InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname, oisAddr, oisPort);
UNSAFE.putObject(this, FIELDS_OFFSET, h);
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("Stream data required");
}
/*▲ 序列化 ████████████████████████████████████████████████████████████████████████████████┛ */
// 检查端口号,必须位于[0, 65535]之间
private static int checkPort(int port) {
if(port<0 || port>0xFFFF) {
throw new IllegalArgumentException("port out of range:" + port);
}
return port;
}
// 检查主机名称,确保不为null
private static String checkHost(String hostname) {
if(hostname == null) {
throw new IllegalArgumentException("hostname can't be null");
}
return hostname;
}
/**
* Compares this object against the specified object.
* The result is {@code true} if and only if the argument is
* not {@code null} and it represents the same address as
* this object.
* <p>
* Two instances of {@code InetSocketAddress} represent the same
* address if both the InetAddresses (or hostnames if it is unresolved) and port
* numbers are equal.
* If both addresses are unresolved, then the hostname and the port number
* are compared.
*
* Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are
* considered equal.
*
* @param obj the object to compare against.
*
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*
* @see java.net.InetAddress#equals(java.lang.Object)
*/
@Override
public final boolean equals(Object obj) {
if(obj == null || !(obj instanceof InetSocketAddress))
return false;
return holder.equals(((InetSocketAddress) obj).holder);
}
/**
* Returns a hashcode for this socket address.
*
* @return a hash code value for this socket address.
*/
@Override
public final int hashCode() {
return holder.hashCode();
}
/**
* Constructs a string representation of this InetSocketAddress.
* This String is constructed by calling toString() on the InetAddress
* and concatenating the port number (with a colon). If the address
* is unresolved then the part before the colon will only contain the hostname.
*
* @return a string representation of this object.
*/
@Override
public String toString() {
return holder.toString();
}
// Private implementation class pointed to by all public methods.
private static class InetSocketAddressHolder {
// The hostname of the Socket Address
private String hostname; // 主机名称
// The IP address of the Socket Address
private InetAddress addr; // 主机地址
// The port number of the Socket Address
private int port; // 主机端口
private InetSocketAddressHolder(String hostname, InetAddress addr, int port) {
this.hostname = hostname;
this.addr = addr;
this.port = port;
}
// 获取端口号
private int getPort() {
return port;
}
// 获取IP地址
private InetAddress getAddress() {
return addr;
}
// 获取主机名称
private String getHostName() {
if(hostname != null) {
return hostname;
}
if(addr != null) {
return addr.getHostName();
}
return null;
}
// 获取主机名称或注解地址
private String getHostString() {
if(hostname != null) {
return hostname;
}
if(addr != null) {
if(addr.holder().getHostName() != null) {
return addr.holder().getHostName();
} else {
return addr.getHostAddress();
}
}
return null;
}
// 判断当前地址是否为一个未解析的socket地址
private boolean isUnresolved() {
return addr == null;
}
@Override
public final boolean equals(Object obj) {
if(obj == null || !(obj instanceof InetSocketAddressHolder)) {
return false;
}
InetSocketAddressHolder that = (InetSocketAddressHolder) obj;
boolean sameIP;
if(addr != null) {
sameIP = addr.equals(that.addr);
} else if(hostname != null) {
sameIP = (that.addr == null) && hostname.equalsIgnoreCase(that.hostname);
} else {
sameIP = (that.addr == null) && (that.hostname == null);
}
return sameIP && (port == that.port);
}
@Override
public final int hashCode() {
if(addr != null) {
return addr.hashCode() + port;
}
if(hostname != null) {
return hostname.toLowerCase().hashCode() + port;
}
return port;
}
@Override
public String toString() {
if(isUnresolved()) {
return hostname + ":" + port;
} else {
return addr.toString() + ":" + port;
}
}
}
}