UDP broadcast search LAN device information

Keywords: Java socket Mobile network

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.

250 original articles published, 139 praised, 400000 visitors+
His message board follow

Posted by teebo on Sun, 19 Jan 2020 23:26:42 -0800