Java Networking: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(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 can 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.  
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; one way to create an unbound socket is to use <tt>DatagramSocket(((SocketAddress)null)</tt>. 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.
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==


{{External|https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html}}
{{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

https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html

InetAddress

https://docs.oracle.com/javase/8/docs/api/java/net/InetAddress.html

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

https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html

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

https://docs.oracle.com/javase/8/docs/api/java/net/Inet6Address.html

SocketAddress

https://docs.oracle.com/javase/8/docs/api/java/net/SocketAddress.html

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

https://docs.oracle.com/javase/8/docs/api/java/net/InetSocketAddress.html

Represents an IP socket address (IP address + port or hostname + port).

NetworkInterface

https://docs.oracle.com/javase/8/docs/api/java/net/NetworkInterface.html

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:

https://github.com/NovaOrdis/playground/blob/master/java/network/NetworkInterface/src/main/java/io/novaordis/playground/java/network/ni/Main.java

InterfaceAddress

https://docs.oracle.com/javase/8/docs/api/java/net/InterfaceAddress.html

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

https://docs.oracle.com/javase/8/docs/api/java/net/DatagramSocket.html

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

https://docs.oracle.com/javase/8/docs/api/java/net/MulticastSocket.html

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

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. 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

Socket Configuration

Subjects