Article directory
What is UDP?
It is a user datagram protocol, also known as user datagram protocol. It is a simple datagram oriented transport layer protocol, with the formal specification of RFC 768. UDP provides a method for applications to send encapsulated IP datagrams without establishing a connection
UDP core API
- Datagram socket: a class used to receive and send UDP messages (send / receive UDP packets). Unlike TCP, UDP is not integrated into the Socket api. This class is both the server and the client
- Datagram packet: that is, UDP message encapsulation class, which is used to process messages, package data such as byte array, destination address and destination port into messages or decompose messages into byte array. It is the sending entity and receiving entity of UDP.
The specific meaning of the target address and port depends on whether the data message is sent or received. If the data message is to be sent, it indicates the ip and port of the receiving end; if the data message is received, it indicates the ip and port of the sending end.
Introduction of datagram socket construction method
- DatagramSocket(): create a simple instance, do not specify the port and IP, let the system automatically allocate
- Datagram socket (int port): create an instance to listen to the fixed port
- Datagram socket (int port, InetAddress localAddr): creates an instance of the specified IP of the fixed port
Common methods of datagram socket
- Receive (datagram packet d): receive a datagram
- Send (datagram packet d): Send a data message
- setSoTimeout(int timeout): set timeout in milliseconds
- close(): close and release resources
The construction method of datagram packet
- Datagram packet (byte buf [], int length, InetAddress address, int port): usually used to send data messages. The first two parameters specify the use range of buf, and the last two parameters specify the address and port of the target machine
- Datagram packet (byte [] buf, int offset, int length, InetAddress address, int port): usually used to send data messages. The first three parameters specify the use range of buf, and the last two parameters specify the address and port of the target machine
- Datagram packet (byte [buf, int length, SocketAddress address]): usually used to send data messages. The first two parameters specify the use interval of buf. SocketAddress is equivalent to InetAddress+Port
- Datagram packet (byte buf [], int length): usually used when receiving data message, parameters are used to specify the length of buf and buf
Common methods of datagram packet
- setData(byte[]buf,int offset,int length): set data of specified length
- setData(byte[]buf): set the full data of buf
- setLength(int length): set the length of buf data
- getData(): get the data in the message
- getOffset(): get the offset of data buf in the message
- getLength(): get the length of data buf in the message
- setAddress(InetAddress iaddr): set the destination address (the sender is used to set the receiver address of datagram)
- setPort(int port): set the target port (the sender is used to set the receiver port of datagram)
- getAddress(): get target address (sender address)
- getPort(): get target port (sender port)
- Setsocketaddress (socketaddress address): set target address + port
- getSocketAddress(): get target address + port
Usually get method is used to get the sender information of the datagram, while set method is used to set the receiver information of the datagram. Of course, if you use the multi parameter construction method, you can reduce the use of set method.
Unicast, broadcast, multicast
- Unicast: point to point transmission of information, not perceived by other points.
- Broadcast: sending information to all terminals will be restricted by the router's isolation and only valid in the same LAN.
- Multicast: also known as multicast, is to send information to a group of points.
Case introduction
The case is divided into UDP providers (i.e. devices searched, such as smart devices in LAN) and UDP searchers (such as mobile phones in LAN).
The function to be completed is to search the unique ID of the intelligent device in the LAN through the mobile phone, assuming that the unique ID is a string of UUID values, and then print it after searching.
The function UDP provider needs to implement is to listen to a specific port circularly, then analyze the received data, judge whether the data conforms to the predetermined format, obtain the response port of the sender from it, and respond the unique identification UUID value to the UDP searcher.
UDP searchers need to realize the functions of listening to specific ports and sending LAN broadcast. When sending broadcast, the listening port is set in the data. Therefore, it is necessary to turn on the listening before sending broadcast. Once the response data is received, the device information can be parsed.
The next step is to start coding. First, a MessageCreator class is used to encapsulate and parse ports and device unique identifiers
/** * Message Creator */ public class MessageCreator { private static final String SN_HEADER = "Receive Port I'm UDPProvider (SN):"; //sn replied by UDPProvider private static final String PORT_HEADER = "I'm UDPSearcher,Please send to (Port):"; //Response port of UDPSearcher public static String buildWithPort(int port) { return PORT_HEADER + port; } public static int parsePort(String data){ if (data.startsWith(PORT_HEADER)) { return Integer.parseInt(data.substring(PORT_HEADER.length())); } return -1; } public static String buildWithSn(String sn) { return SN_HEADER + sn; } public static String parseSn(String data){ if (data.startsWith(SN_HEADER)) { return data.substring(SN_HEADER.length()); } return null; } }
Then the UDPProvider class
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.util.UUID; /** * UDP Provider, for providing services */ public class UDPProvider { public static void main(String[] args) throws IOException { //Generate a unique ID String sn = UUID.randomUUID().toString(); Provider provider = new Provider(sn); provider.start(); //Read any character to exit System.in.read(); provider.exit(); } private static class Provider extends Thread { private final String sn; private boolean done = false; private DatagramSocket ds = null; public Provider(String sn) { super(); this.sn = sn; } @Override public void run() { super.run(); System.out.println("UDPProvider Started"); try { // As the receiver, specify a port for data receiving ds = new DatagramSocket(20000); while (!done) { //Build receiving entity final byte[] buf = new byte[512]; DatagramPacket receivePack = new DatagramPacket(buf, buf.length); //Start receiving ds.receive(receivePack); //Print received information and sender's information String ip = receivePack.getAddress().getHostAddress();//Sender's ip int port = receivePack.getPort();//Sender's port int dataLen = receivePack.getLength();//Packet length String data = new String(receivePack.getData(), 0, dataLen);//Data content //Print sender ip / port / data System.out.println("UDPProvider receive from ip:" + ip + "\tport:" + port + "\tdata:" + data); //Resolve response port number int responsePort = MessageCreator.parsePort(data); if (responsePort != -1) { //Build a loopback data to return the sn of the device to the searcher String responseData = MessageCreator.buildWithSn(sn); byte[] responseDataBytes = responseData.getBytes(); //Build a loopback message directly from the sender DatagramPacket responsePacket = new DatagramPacket(responseDataBytes, responseDataBytes.length, receivePack.getAddress(),//The sender's ip is designated as the receiver's ip responsePort); //Loopback to specified port ds.send(responsePacket); } } } catch (Exception ignored) { } finally { close(); } //complete System.out.println("UDPProvider Finished"); } private void close() { if (null != ds) { ds.close(); ds = null; } } /** * End */ void exit() { done = true; close(); } } }
Finally, the UDPSearcher class
import java.io.IOException; import java.net.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; /** * UDP Searcher */ public class UDPSearcher { //Monitor loopback port number private static final int LISTENER_PORT = 30000; public static void main(String[] args) throws IOException, InterruptedException { System.out.println("UDPSearcher Started"); //Enable listening 30000 port Listener listener = listen(); //Transmit broadcast sendBroadcast(); //End of reading any information System.in.read(); List<Device> devices = listener.getDevicesAndClose(); for (Device device : devices) { System.out.println("Device:" + device.toString()); } System.out.println("UDPSearcher Finished"); } /** * Listen for UDP provider responses */ private static Listener listen() throws InterruptedException { System.out.println("UDPSearcher start listen"); CountDownLatch countDownLatch = new CountDownLatch(1); Listener listener = new Listener(LISTENER_PORT, countDownLatch); listener.start(); countDownLatch.await(); //Wait for the monitor to start. This is blocked return listener;//Back to monitor after startup } /** * Send broadcast start search UDP provider * * @throws IOException */ private static void sendBroadcast() throws IOException { System.out.println("UDPSearcher sendBroadcast Started"); // As a searcher, it is unnecessary to specify a port for the system to assign automatically DatagramSocket ds = new DatagramSocket(); //Send a request data and expose the listening port String requestData = MessageCreator.buildWithPort(LISTENER_PORT); byte[] requestDataBytes = requestData.getBytes(); //Create a datagram packet DatagramPacket requestPacket = new DatagramPacket(requestDataBytes, requestDataBytes.length); //Specify the ip address of the receiver. Since it is received locally, localhost can be used //requestPacket.setAddress(InetAddress.getLocalHost()); //Or you can specify the specific ip address of the receiver. Here, the limited broadcast address is used //requestPacket.setAddress(InetAddress.getByName("255.255.255.255")); //Send to specific network segment broadcast address requestPacket.setAddress(InetAddress.getByName("192.168.1.255")); //Specify the port number of the receiver requestPacket.setPort(20000); //Start broadcast ds.send(requestPacket); ds.close(); //Send broadcast complete System.out.println("UDPSearcher sendBroadcast Finished"); } /** * Target device (UDP provider) */ private static class Device { final int port; final String ip; final String sn; public Device(int port, String ip, String sn) { this.port = port; this.ip = ip; this.sn = sn; } @Override public String toString() { return "Device{" + "port=" + port + ", ip='" + ip + '\'' + ", sn='" + sn + '\'' + '}'; } } //Listen Thread private static class Listener extends Thread { private final int listenPort; private final CountDownLatch countDownLatch; private final List<Device> devices = new ArrayList<>(); private boolean done = false; private DatagramSocket ds = null; public Listener(int listenPort, CountDownLatch countDownLatch) { super(); this.listenPort = listenPort; this.countDownLatch = countDownLatch; } @Override public void run() { super.run(); //Notification started countDownLatch.countDown(); try { //Listening loopback port ds = new DatagramSocket(listenPort); while (!done) { //Build receiving entity final byte[] buf = new byte[512]; DatagramPacket receivePack = new DatagramPacket(buf, buf.length); //Start receiving ds.receive(receivePack); //Print received information and sender's information String ip = receivePack.getAddress().getHostAddress();//Sender's ip int port = receivePack.getPort();//Sender's port int dataLen = receivePack.getLength();//Packet length String data = new String(receivePack.getData(), 0, dataLen);//Data content System.out.println("UDPSearcher receive from ip:" + ip + "\tport:" + port + "\tdata:" + data); //Parse sn and add devices String sn = MessageCreator.parseSn(data); if (null != sn) { Device device = new Device(port, ip, sn); devices.add(device); } } } catch (Exception e) { } finally { close(); } System.out.println("UDPSearcher listener finished"); } private void close() { if (null != ds) { ds.close(); ds = null; } } List<Device> getDevicesAndClose() { done = true; close(); return devices; } } }
test
First, turn on UDPProvider to listen to the broadcast and send the device information to the searcher
Then turn on UDPSearcher, which is used to send broadcast and listen to its specific port to obtain device information
You can see that two devices have been searched at the same time.