Java Networking: Difference between revisions
(→Socket) |
|||
(27 intermediate revisions by the same user not shown) | |||
Line 18: | Line 18: | ||
{{External|https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html}} | {{External|https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html}} | ||
====Building a Simple IPV4 InetAddress==== | |||
<pre> | |||
InetAddress ipv4Addr = Inet4Address.getByAddress( | |||
new byte[] {(byte)172, (byte)31, (byte)25, (byte)44})); | |||
assertEquals("/172.31.25.44", ipv4Addr.toString()); | |||
ipv4Addr = InetAddress.getByName("172.31.25.44"); | |||
assertEquals("/172.31.25.44", ipv4Addr.toString()); | |||
</pre> | |||
===Inet6Address=== | ===Inet6Address=== | ||
Line 98: | Line 108: | ||
Datagram sockets are used to send and receive datagram packets. Each packet is individually addressed and routed, so multiple packets sent from one machine may be routed differently and may arrive in any order. | Datagram sockets are used to send and receive datagram packets. Each packet is individually addressed and routed, so multiple packets sent from one machine may be routed differently and may arrive in any order. | ||
A datagram socket | A datagram socket must be ''bound'' to a specific local address and port in order to be able to send and receive packets. The packets that are then sent via the socket carry as "source" address and port the IP address and port the socket is bound to. | ||
Most constructors automatically bind the sockets they create to the address and port specified as arguments | Most constructors automatically bind the sockets they create to the address and port specified as arguments. If the constructor does not have an address argument, a [[#Wildcard_Address|wildcard address]] will be used, and the socket will be bound to a valid local address. If the constructor does not have a port argument, the socket will be bound to any available port. If an unbound socket is needed, it must be created with <tt>DatagramSocket(((SocketAddress)null)</tt>. | ||
The binding state of a socket can be checked with <tt>isBound()</tt>. Once bound, the local address and port the socket is bound to can be checked with <tt>getLocalSocketAddress()</tt>. The same information is returned individually by <tt>getLocalAddress()</tt>/<tt>getLocalPort()</tt>. If the socket is explicitly bound to a null address, then an [[#Ephemeral_Port|ephemeral port]] and a valid local address will be used. | The binding state of a socket can be checked with <tt>isBound()</tt>. Once bound, the local address and port the socket is bound to can be checked with <tt>getLocalSocketAddress()</tt>. The same information is returned individually by <tt>getLocalAddress()</tt>/<tt>getLocalPort()</tt>. If the socket is explicitly bound to a null address with <tt>bind(null)</tt>, then an [[#Ephemeral_Port|ephemeral port]] and a valid local address will be used. | ||
A bound socket can be used to send datagram to any IP address/port. | A bound socket can be used to send datagram to any IP address/port. | ||
Packets are send with <tt>send(DatagramPacket p)</tt>. Packets are received with <tt>receive(DatagramPacket p)</tt>. When <tt>receive()</tt> method returns, the DatagramPacket's buffer is filled with the data received. The datagram packet contains the sender's IP address and the port number of the sender's machine. The method blocks until a datagram is received. | |||
A datagram socket can be explicitly ''connected'' to a specific remote address and port. When a socket is connected to a remote address, packets may only be sent to or received from that address. By default a datagram socket is not connected. If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. The connected state of a socket can be checked with <tt>isConnected()</tt>. When connected, the remote endpoint information can be obtained with <tt>getRemoteSocketAddress()</tt> or <tt>getInetAddress()</tt> and <tt>getPort()</tt>. | A datagram socket can be explicitly ''connected'' to a specific remote address and port. When a socket is connected to a remote address, packets may only be sent to or received from that address. By default a datagram socket is not connected. If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. The connected state of a socket can be checked with <tt>isConnected()</tt>. When connected, the remote endpoint information can be obtained with <tt>getRemoteSocketAddress()</tt> or <tt>getInetAddress()</tt> and <tt>getPort()</tt>. | ||
A socket connected to a multicast address may only be used to send packets. | A socket connected to a multicast address may only be used to send packets. | ||
The traffic class or type-of-service in the IP datagram header for packets sent from a DatagramSocket can be obtained/set with <tt>getTrafficClass()</tt>/<tt>setTrafficClass()</tt>. | |||
===DatagramSocket Configuration=== | ===DatagramSocket Configuration=== | ||
* <span id="DatagramSocket_SO_RCVBUF"></span>[[Socket SO_RCVBUF|SO_RCVBUF]] | * <span id="DatagramSocket_SO_RCVBUF"></span>[[Socket SO_RCVBUF|SO_RCVBUF]] | ||
* <span id="DatagramSocket_SO_SNDBUF"></span>[[Socket SO_SNDBUF|SO_SNDBUF]] | |||
* <span id="DatagramSocket_SO_REUSEADDR"></span>[[Socket SO_REUSEADDR|SO_REUSEADDR]] | |||
* <span id="DatagramSocket_SO_TIMEOUT"></span>[[Socket SO_TIMEOUT|SO_TIMEOUT]] | |||
* <span id="DatagramSocket_SO_BROADCAST"></span>[[Socket SO_BROADCAST|SO_BROADCAST]] | |||
==MulticastSocket== | ==MulticastSocket== | ||
Line 118: | Line 136: | ||
A <tt>MulticastSocket</tt> is a [[#DatagramSocket|DatagramSocket]], the class inherits from <tt>DatagramSocket</tt>. | A <tt>MulticastSocket</tt> is a [[#DatagramSocket|DatagramSocket]], the class inherits from <tt>DatagramSocket</tt>. | ||
A <tt>MulticastSocket</tt> will bind by default to an interface that is multicast enabled, and services multicast routing. If no explicit multicast route is defined, multicast sockets will be bound to the interface that services the default route, even if the socket is instructed to bind to a different interface. | |||
===Failure to Initialize a Multicast Socket=== | |||
The failure to initialize a multicast socket on 127.0.0.1 with the exception shown below | |||
<pre> | |||
15:09:20,151 ERROR [org.hornetq.core.server] (Thread-0 (HornetQ-scheduled-threads-1459186470)) HQ224033: Failed to broadcast connector configs: java.io.IOException: Can't assign requested address | |||
at java.net.PlainDatagramSocketImpl.send(Native Method) [rt.jar:1.8.0_25] | |||
at java.net.DatagramSocket.send(DatagramSocket.java:693) [rt.jar:1.8.0_25] | |||
at org.hornetq.api.core.UDPBroadcastGroupConfiguration$UDPBroadcastEndpoint.broadcast(UDPBroadcastGroupConfiguration.java:136) [hornetq-core-client-2.3.25.SP18-redhat-1.jar:2.3.25.SP18-redhat-1] | |||
[...] | |||
</pre> | |||
can be fixed by adding a multicast route to 127.0.0.1, as shown here: [[Linux_Routing_Configuration#Adding_Multicast_Routing_to_a_Specific_Network_Interface|Adding Multicast Routing to a Specific Network Interface]]. | |||
==Socket== | ==Socket== | ||
{{ | {{External2|https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html|https://docs.oracle.com/javase/8/docs/api/java/net/SocketOptions.html}} | ||
A TCP Socket. | A TCP Socket. The TCP socket is connected using the following API: | ||
<pre> | |||
Socket.connect(SocketAddress endpoint, int timeout); | |||
</pre> | |||
where "timeout" represents the interval in milliseconds after which the connection attempt is abandoned by trowing a SocketTimeoutException if the connection cannot be established. A timeout of zero is interpreted as an infinite timeout. | |||
===IPv4/IPv6=== | |||
If IPv6 is available on the operating system the underlying native socket will be, by default, an IPv6 socket which lets applications connect to, and accept connections from, both IPv4 and IPv6 hosts. However, in the case an application would rather use IPv4 only sockets, set: | |||
<pre> | |||
-Djava.net.preferIPv4Stack=true | |||
</pre> | |||
===Socket Configuration=== | ===Socket Configuration=== | ||
* <span id="Socket_SO_RCVBUF"></span>[[Socket SO_RCVBUF|SO_RCVBUF]] | * <span id="Socket_SO_RCVBUF"></span>[[Socket SO_RCVBUF|SO_RCVBUF]] | ||
* <span id="Socket_SO_SNDBUF"></span>[[Socket SO_SNDBUF|SO_SNDBUF]] | |||
* <span id="Socket_SO_REUSEADDR"></span>[[Socket SO_REUSEADDR|SO_REUSEADDR]] | |||
* <span id="Socket_SO_TIMEOUT"></span>[[Socket SO_TIMEOUT|SO_TIMEOUT]] | |||
* <span id="Socket_SO_BROADCAST"></span>[[Socket SO_BROADCAST|SO_BROADCAST]] | |||
* <span id="Socket_SO_KEEPALIVE"></span>[[Socket SO_KEEPALIVE|SO_KEEPALIVE]] | |||
* <span id="Socket_SO_LINGER"></span>[[Socket SO_LINGER|SO_LINGER]] | |||
* [[Socket_TCP_NODELAY|TCP_NODELAY]] | |||
=Subjects= | |||
* [[Java Networking - Common Socket Exceptions|Common Socket Exceptions]] | |||
* [[Java Network Traffic Generator]] | |||
* [https://github.com/NovaOrdis/playground/tree/master/java/nio/tcp Simple Playground Client/Server Application to Experiment with Sockets] |
Latest revision as of 18:23, 26 July 2018
Internal
Concepts
Networking Properties
InetAddress
This class represents an Internet Protocol (IP) address. Its subclasses represent either 32 bit IPv4 addresses (Inet4Address) or an 128 bit IPv6 addresses (Inet6Address). The instances incapsulate the numeric address (4 bytes or 16 bytes) and possibly a host name, but not netmask information. The class has accessors that characterize the IP address (isMulticastAddress() etc.).
Inet4Address
Building a Simple IPV4 InetAddress
InetAddress ipv4Addr = Inet4Address.getByAddress( new byte[] {(byte)172, (byte)31, (byte)25, (byte)44})); assertEquals("/172.31.25.44", ipv4Addr.toString()); ipv4Addr = InetAddress.getByName("172.31.25.44"); assertEquals("/172.31.25.44", ipv4Addr.toString());
Inet6Address
SocketAddress
Is an immutable representation of a socket address. It does not have any association with any protocol. The values are used by sockets for binding, connecting or as returned values.
InetSocketAddress
Represents an IP socket address (IP address + port or hostname + port).
NetworkInterface
The JVM representation of a network interface available on the host. It is identified by a name, the same name returned by ifconfig -a or ip addr, if the host runs a Unix system. The NetworkInterface instance can be used to get the list of addresses associated with the interface and other characteristics of the interface.
Comparison between the information visible from JVM and directly from the system with ip addr:
1. lo <LOOPBACK, UP> mtu 65536 hardware address: N/A interface addresses: 0:0:0:0:0:0:0:1%lo/128, 127.0.0.1/8 2. eth0 <UP, MULTICAST> mtu 1500 hardware address: 08:00:27:2c:e2:de interface addresses: fe80:0:0:0:a00:27ff:fe2c:e2de%eth0/64, 10.0.2.15/24 3. eth1 <UP, MULTICAST> mtu 1500 hardware address: 08:00:27:95:52:f2 interface addresses: fe80:0:0:0:a00:27ff:fe95:52f2%eth1/64, 172.20.1.11/16
ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:2c:e2:de brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0 valid_lft 84095sec preferred_lft 84095sec inet6 fe80::a00:27ff:fe2c:e2de/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:95:52:f2 brd ff:ff:ff:ff:ff:ff inet 172.20.1.11/16 brd 172.20.255.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe95:52f2/64 scope link valid_lft forever preferred_lft forever
NetworkInterface code in GitHub:
InterfaceAddress
Represents a NetworkInterface address. For an IPv4 address, It consists of an IP address, a subnet mask and a broadcast address. For an IPv6 address, it consists in an IP address and a network prefix length.
Wildcard Address
An address chosen by the kernel. Java network API indicates that a wildcard address is desired by specifying "0.0.0.0".
InetAddress.isAnyLocalAddress() returns true on InetAddress wildcard address representation.
Ephemeral Port
DatagramSocket
Datagram sockets are used to send and receive datagram packets. Each packet is individually addressed and routed, so multiple packets sent from one machine may be routed differently and may arrive in any order.
A datagram socket must be bound to a specific local address and port in order to be able to send and receive packets. The packets that are then sent via the socket carry as "source" address and port the IP address and port the socket is bound to.
Most constructors automatically bind the sockets they create to the address and port specified as arguments. If the constructor does not have an address argument, a wildcard address will be used, and the socket will be bound to a valid local address. If the constructor does not have a port argument, the socket will be bound to any available port. If an unbound socket is needed, it must be created with DatagramSocket(((SocketAddress)null).
The binding state of a socket can be checked with isBound(). Once bound, the local address and port the socket is bound to can be checked with getLocalSocketAddress(). The same information is returned individually by getLocalAddress()/getLocalPort(). If the socket is explicitly bound to a null address with bind(null), then an ephemeral port and a valid local address will be used.
A bound socket can be used to send datagram to any IP address/port.
Packets are send with send(DatagramPacket p). Packets are received with receive(DatagramPacket p). When receive() method returns, the DatagramPacket's buffer is filled with the data received. The datagram packet contains the sender's IP address and the port number of the sender's machine. The method blocks until a datagram is received.
A datagram socket can be explicitly connected to a specific remote address and port. When a socket is connected to a remote address, packets may only be sent to or received from that address. By default a datagram socket is not connected. If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. The connected state of a socket can be checked with isConnected(). When connected, the remote endpoint information can be obtained with getRemoteSocketAddress() or getInetAddress() and getPort().
A socket connected to a multicast address may only be used to send packets.
The traffic class or type-of-service in the IP datagram header for packets sent from a DatagramSocket can be obtained/set with getTrafficClass()/setTrafficClass().
DatagramSocket Configuration
MulticastSocket
A MulticastSocket is a DatagramSocket, the class inherits from DatagramSocket.
A MulticastSocket will bind by default to an interface that is multicast enabled, and services multicast routing. If no explicit multicast route is defined, multicast sockets will be bound to the interface that services the default route, even if the socket is instructed to bind to a different interface.
Failure to Initialize a Multicast Socket
The failure to initialize a multicast socket on 127.0.0.1 with the exception shown below
15:09:20,151 ERROR [org.hornetq.core.server] (Thread-0 (HornetQ-scheduled-threads-1459186470)) HQ224033: Failed to broadcast connector configs: java.io.IOException: Can't assign requested address at java.net.PlainDatagramSocketImpl.send(Native Method) [rt.jar:1.8.0_25] at java.net.DatagramSocket.send(DatagramSocket.java:693) [rt.jar:1.8.0_25] at org.hornetq.api.core.UDPBroadcastGroupConfiguration$UDPBroadcastEndpoint.broadcast(UDPBroadcastGroupConfiguration.java:136) [hornetq-core-client-2.3.25.SP18-redhat-1.jar:2.3.25.SP18-redhat-1] [...]
can be fixed by adding a multicast route to 127.0.0.1, as shown here: Adding Multicast Routing to a Specific Network Interface.
Socket
A TCP Socket. The TCP socket is connected using the following API:
Socket.connect(SocketAddress endpoint, int timeout);
where "timeout" represents the interval in milliseconds after which the connection attempt is abandoned by trowing a SocketTimeoutException if the connection cannot be established. A timeout of zero is interpreted as an infinite timeout.
IPv4/IPv6
If IPv6 is available on the operating system the underlying native socket will be, by default, an IPv6 socket which lets applications connect to, and accept connections from, both IPv4 and IPv6 hosts. However, in the case an application would rather use IPv4 only sockets, set:
-Djava.net.preferIPv4Stack=true