This is the 7th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

Last blog in Java network programming (six) – UDP programming (a) – Digging gold (juejin. Cn) preliminary introduction to UDP programming, and gave a simple EXAMPLE of UDP communication, but due to the length of the problem, did not expand details, In this blog post I will focus on the DatagramPacket class and the DatagramSocket class

DatagramPacket

The constructor

The form of the DatagramPacket constructor depends on whether the DatagramPacket is used to send or receive data. The first group is the DatagramPacket to receive. Its constructors take at least two arguments, one is the byte array that holds the datagram data, and the other is the number of bytes in the array used for the datagram data. When the socket receives a datagram from the network, it stores the DatagramPacket data in the buffer array of the DatagramPacket object until it reaches the length you specify.

The second set of DatagramPacket constructors is used to create datagrams sent over the network. These constructors require an array of buffers and a length, as well as specifying the address and port to which the packet is sent. In this case, you pass the constructor a byte array containing the data you want to send, along with the destination address and port to which the packet will be sent. DatagramSocket reads the destination address and port from the packet. The address and port are not stored in the Socket, as is the case with TCP.

A constructor that receives datagrams

The following two functions are used to construct a DatagramPacket that accepts data from the network:

public DatagramPacket(byte[] buffer, int length)
public DatagramPacket(byte[] buffer, int offset, int length)
Copy the code

The first constructor is that when the Socket receives a datagram, it stores the data portion of the datagram in buffer, starting with Buffer [o], until the packet is fully stored, or until a length byte has been written to buffer. The second constructor will store from buffer[offset]. Other than that, the two constructors are identical.

The constructor doesn’t care how big the buffer is, it even happily lets you create megabytes of Datagrampackets. However, underlying networking software is less forgiving, and most underlying UDP implementations do not support datagrams that exceed 8192 bytes of data. In fact, many UDP-based protocols, such as DNS and TFTP, use packets with 512 bytes or less of data per datagram. The maximum data size commonly used is 8192 bytes for NFS. Almost all UDP datagrams you are likely to encounter have 8KB or less of data. Therefore, do not create DatagramPacket objects with more than 8192 bytes of data.

For example, the following code creates a new DatagramPacket that can accept datagrams up to 8192:

byte[ ] buffer = new byte[8192];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
Copy the code

Constructor that sends datagrams

The following four functions are used to construct a DatagramPacket that sends data over the network:

public DatagramPacket(byte[] data,int length, InetAddress destination,int port)
public DatagramPacket(byte[] data,int offset, int length, InetAddress destination, int port)
public DatagramPacket(byte[] data, int length, SocketAddress destination)
public DatagramPacket(byte[] data, int offset, int length, SocketAddress destination)
Copy the code

Each constructor creates a new DatagramPacket to be sent to another host. The package is filled with length bytes from the Data array starting with offset (or 0 if offset is not used). The destination of the InetAddress or SocketAddress object points to the destination host to which the packet is sent, and the parameter port is the port on that host.

Before creating a DatagramPacket, convert the data to a byte array and place it in data, but this is not absolutely necessary. Data can be modified after datagrams are constructed and before they are sent. In some applications, you can take advantage of this. For example, you can store data that changes over time in Data and send the current datagram (the latest data) every minute.

For example, the following code block creates a new DatagramPacket to send with the data “HELLO WORLD” :

String s = "HELLO WORLD";
byte[] data = s.getBytes(StandardCharsets.UTF_8);
try {
     InetAddress inetAddress = InetAddress.getByName("localhost");
     int port  = 5555;
     DatagramPacket dp = new DatagramPacket(data, data.length, inetAddress, port);
     /* The code to send the datagram */
}catch (IOException E){   
}
Copy the code

The get method

Here are six ways to get the different contents of a datagram from the DatagramPacket class:

public InetAddress getAddress()

The getAddress() method returns an InetAddress object containing the address of the remote host. If the datagram is received from the Internet, the address returned is the source address from which the datagram was sent. If the datagram is created locally and sent to a remote machine, this method returns the address of the target host to which the datagram will be sent. This method is often used to determine the host address from which the UDP datagram is sent so that the recipient can reply.

public int getPort()

The getPort() method returns an integer indicating the remote port. If the datagram is received from the Internet, this is the port on the host that sent the packet. If the datagram is created locally and sent to a remote host, the destination port number to which it was sent is returned.

public SocketAddress getSocketAddress()

The getSocketAddress() method returns a SocketAddress object containing the IP address and port of the remote host. As in the case of getInetAddress(), if the datagram is received from the Internet, the return is the source address. If a datagram is created locally and sent to a remote machine, this method returns the destination address.

public byte[] getData()

The getData() method returns a byte array containing the data in the datagram. In order to be usable in your program, you usually have to convert these bytes to some other form of data. One way is to convert the byte array to a String. For example, we can convert it to a UTF-8 String:

String s = new String(dp.getData(),"UTF-8");
Copy the code

public int getLength()

The getLength() method returns the number of bytes of data in the datagram. It is not necessarily equal to the length of the array returned by getData(). The int returned by getLength() may be less than the array length returned by getData().

public int getOffset()

For the array returned by getData(), this method returns a location in the array where the datagram data began to be populated.

Set method

The DatagramPacket also provides several methods to change the data, remote address, and remote port after the datagram is created. These methods are important if the time to create and garbage collect a new DatagramPacket object severely affects performance — in some cases, it is much faster to reuse objects than to construct new ones.

public void setData(byte[] data)

The setData() method changes the UDP datagram payload. You might use this method if you want to send large files (larger than a datagram can contain) to a remote host. You can send the same DatagramPacket object repeatedly, changing only the data each time.

public void setData(byte[] data, int offset, int length)

This overloaded setData() method provides another way to send large amounts of data. Instead of sending lots of new arrays, you can put all the data in one array, one part at a time. For example, the following loop sends a large array in 512-byte blocks:

int offset = 0;
DatagramPacket dp = new DatagramPacket(bigarray,offset,512);
int bytesSent = 0;
while (bytesSent < bigarray. length) {
	socket.send(dp);
	bytesSent += dp.getLength();
	int bytesToSend = bigarray. length - bytesSent;
	int size = (bytesToSend > 512)? 512 : bytesToSend;
	dp.setData(bigarray, bytesSent, size);
}
Copy the code

public void setAddress(InetAddress remote)

The setAddress() method modifies the address to which the datagram is sent. This allows you to send the same datagram to multiple different recipients.

public void setPort(int port)

The setPort() method changes the port to which the datagram is sent.

public void setAddress(SocketAddress remote)

The setSocketAddress() method changes the address and port to which the datagram packet is sent. You can use this method when replying. For example, the following code snippet will receive a datagram packet that responds to the same address with a packet containing the string “Hello there” :

DatagramPacket input = new DatagramPacket(new byte[8192].8192);
socket.receive(input);
DatagramPacket output = new DatagramPacket("Hello there".getBytes("UTF-8"),11);
SocketAddress address = input.getSocketAddress();
output.setAddress(address);
socket.send(output);
Copy the code

public void setLength(int length)

The setLength() method changes the number of bytes in the internal buffer that contain the actual datagram data, not the space that contains the unfilled data.

DatagramSocket

To send and receive datagrampackets, a datagram Socket must be opened. In Java, datagramsockets are created and accessed through the DatagramSocket class. All datagramsockets are bound to a local port on which they listen for inbound data. If you want to write a client that doesn’t care about the local port, you can call a constructor and let the system allocate an unused port (anonymous port). This port number will be placed in the outgoing datagram and will be used by the server to determine the sending address of the response datagram. If you’re writing a server, the client needs to know on which port the server listens for inbound datagrams. Therefore, when the server constructs the DatagramSocket, it specifies the local port on which it listens. However, the sockets used by the client and server are the same: the difference is only between anonymous and known ports. There is no difference between a client Socket and a server Socket, as in TCP. There is no such thing as a DatagramServerSocket.

The constructor

public DatagramSocket() throws SocketException

This constructor creates a Socket bound to an anonymous port. ,

public DatagramSocket(int port) throws SocketException

This constructor creates a Socket that listens for inbound datagrams on the specified port (specified by the port argument). You can use this constructor to write servers that listen on known ports. The TCP port is not associated with the UDP port. Two different programs can use the same port number if one uses UDP and the other uses TCP.

public DatagramSocket(int port, InetAddress interface) throwsSocketException

This constructor is intended for multi-host hosts and creates sockets that listen for inbound datagrams at specified ports and network interfaces. The address parameter is an InetAddress object that matches a network interface of the host.

public DatagramSocket(SocketAddress interface) throwsSocketException

This constructor is similar to the previous one, except that the network interface address and port are read by SocketAddress. For example, the following code snippet creates a Socket that listens only for the local loopback address:

SocketAddress address = new InetSocketAddress("127.0.0.1".9999);
DatagramSocket socket = new DatagramSocket(address);
Copy the code

Send and receive datagrams

The DatagramSocket class sends and receives UDP datagrams. A Socket can both send and receive datagrams. In fact, it can send and receive data to multiple hosts at the same time.

public void send(DatagramPacket dp) throws lOException

Once the DatagramPacket is created and the DatagramSocket is constructed, the packet can be sent by passing it to the Socket’s send() method. For example, if theSocket is a DatagramSocket object and theOutput is a DatagramPacket object, we can use theSocket to send theOutput as follows:

theSocket.send(theOutput);
Copy the code

public void receive(DatagramPacket dp) throws IOException

This method receives a UDP datagram from the network and stores it in the existing DatagramPacket object DP. Similar to accept() of the ServerSocket class, this method blocks the calling thread until the datagram arrives. If your program does anything other than wait for datagrams, it should call receive() in a separate thread.

public void close()

Calling the close() method of the DatagramSocket object frees the port occupied by the Socket. As with streams and tcpsockets, you may need to close the datagram Socket ina finally block:

DatagramSocket server = null
try {
server = new DatagramSocket();
} catch (IOException ex) iSystem.err.println(ex);
}finally {
	try {
		if(server ! =null) server.close();
		} catch (IOException ex) {
}
Copy the code

public int getLocalPort()

The getLocalPort() method of the DatagramSocket returns an int indicating the local port on which the Socket is listening. This method can be used if you create a DatagramSocket with an anonymous port and want to figure out the port assigned to the Socket.

public InetAddress getLocalAddress()

The getLocalAddress() method of the DatagramSocket returns an InetAddress object representing the local address to which the Socket is bound.

public SocketAddress getLocalSocketAddress()

The getLocalSocketAddress() method returns a SocketAddress object that wraps the local interface and port to which the Socket is bound.

Manage connections

Unlike TCP sockets, datagram sockets don’t care much about who they talk to. In fact, they can talk to anyone by default, and by using the following five methods, you can select the host that allows sending and receiving datagrams and reject all other hosts’ packets.

public void connect(InetAddress host, int port)

The connect() method doesn’t really establish a connection in the TCP sense. It does, however, specify the DatagramSocket to send and receive packets only to specified remote hosts and specified remote ports.

public void disconnect()

The disconnect() method disconnects the “connection” that has been connected to the DatagramSocket, allowing it to send and receive packets again from any host and port.

public int getPort()

The getPort() method returns the remote port to which it is connected if and only if the DatagramSocket is connected. Otherwise -1 is returned.

public InetAddress getInetAddress()

The getInetAddress() method returns the address of the remote host to which it connects if and only if the DatagramSocket is connected. Otherwise null is returned.

public InetAddress getRemoteSocketAddress()

If the DatagramSocket is connected, getRemoteSocketAddress() returns the address of the remote host to which it is connected. Otherwise null is returned.