To prepare

This article will take Android to find the IP of the NodeJs server deployed in the LAN as the target to achieve the case. For those of you who have not paid much attention to the Internet for a long time, many basic concepts may be easy to remember. In this section, I will briefly introduce the relevant network concepts used in blogs to pave the way for this article.

A network request

Our most familiar with the HTTP protocol, for one, through the HTTP protocol to send a request to the server, the request contained in the agreement calls for a source address, destination address, message entity (data) * * * * and other, usually by TCP is sent to the specified server IP, server by listening to a port, found we sent the request and response, The request is completed. An HTTP request routes through a four-tier TCP/IP protocol cluster as shown in the figure below.

DHCP

Dynamic Host Configuration Protocol is an application-layer Protocol. This agreement gives all devices connected to the LAN a time-limited non-conflicting IP address. That is, the IP of the device is dynamic within the LAN. IP is defined by the network layer IP protocol. If you do not have the IP address of the target device or the destination address, you cannot send the request.

Note: Dynamic IP address assignment is only one of the MECHANISMS used by DHCP to assign IP addresses. However, most routers use this mode by default. This article addresses the same problem of this mechanism.

Unicast, multicast, broadcast

There are three communication mechanisms between devices: unicast, multicast, and broadcast. The division of these communication modes is defined by the network layer IP protocol. The IP protocol specifies the source IP address and destination IP address. There can be only one source IP address and one or more destination IP addresses. According to the number of destination addresses, it can be divided into two types: unicast with unique destination addresses; Multicast and broadcast that can have multiple destination addresses. Unicasting is easy. Next, multicast and broadcast.

multicast

Multicast address

IP address reserved for multicast: 224.0.0.0 to 239.255.255.255. This segment is also divided into different IP addresses, but it does not matter in LAN.

Multicast characteristic

  • Only the members of a specific multicast group can receive multicast data.
  • The source address only needs to send one piece of data;
  • Only one piece of data is transmitted on any route from the source address to the destination address.

The figure illustrates how data is multicast from source address to destination address. In the figure, we can find two obvious characteristics of multicast data transmission: ** First, the source address will only send one data, and the following data are all replicated and forwarded by the router; The other is that only one piece of data is transmitted in any path from the source address to the destination address. ** These two features enable multicast to have high utilization of network resources in one-to-many scenarios. Copy – forward or address – join are implemented by multicast protocols. It just so happens that each platform has a library to implement it. When a device exits the multicast group, data from the source address is not sent to it.

radio

Speaking of broadcast, we must first mention a concept: broadcast domain. A broadcast domain is the area in which a broadcast can be transmitted. The device to which a router is linked is a broadcast domain, but the router does not forward the broadcast, that is, the broadcast cannot be sent out of the LAN, nor to the LAN of another router that is linked to the LAN. A broadcast transmits data by sending a packet to a broadcast address from any device in the broadcast domain, and all other devices in the entire broadcast domain receive the packet. Convenient, isn’t it? Yeah, it’s pretty simple. But there are some downsides to radio:

  • After receiving the data, each device consumes the resource area to process the data. If the destination address is not the destination address, the device discards the packet. In this way, the resources of the non-destination address are wasted.
  • In IPv6, broadcast is disabled!!

Scenario V1.0 — Broadcast implementation

The advantage of broadcast over multicast is that it is very simple and easy to figure out the programming ideas. The idea of using broadcast is that the server sends a broadcast packet of “I am the server”. Android listens to the port agreed between itself and the server. When it finds a packet of “I am the server” in the data, it resolves the source IP address of the packet as the server IP address. The implementation is as follows: sendbroad.js (NodeJs)

const dgram = require("dgram");
const server = dgram.createSocket("udp4");

const message = Buffer.from("this is nodejs server"."ascii");
server.bind(function () {
  server.setBroadcast(true);
});
const interval = setInterval(() = > {
  if (i> 5) {
    console.log("Off the air.");
    server.close()
    clearInterval(interval);
  }else{
    server.send(message, 4000."255.255.255.255." ");
    console.log('Broadcast data No.${i++}`); }},1000,i=0);
Copy the code

The Dgram module provides an implementation of UDP packet sockets. General each platform for dGRAM such libraries are called socket programming library (network programming library), as the name implies is to provide the library of network programming, generally divided into TCP network programming and UDP network programming. Remember the original TCP/IP four-tier architecture diagram, the purpose of the network programming library was to provide layer 2 transport API for the topmost application layer. Let’s start talking about code

const dgram = require("dgram");
const server = dgram.createSocket("udp4");
Copy the code

First, create a UDP socket instance;

const message = Buffer.from("this is nodejs server"."ascii");
Copy the code

Then we prepared a “code” agreed with the client, and converted it into binary, so that it can be transmitted in the network;

server.bind(function () {
  server.setBroadcast(true);
});
Copy the code

Set to broadcast;

const interval = setInterval(() = > {
  if (i> 5) {...clearInterval(interval); }},1000,i=0);
Copy the code

Do something every 1s to turn off the timer five times.

server.send(message, 4000."255.255.255.255." ");
Copy the code

Send a data set to port 4000 with broadcast address 255.255.255.255. Each device listening to 4000 in the broadcast domain receives this data.

In this case, all devices under a route can receive the packet. The following is the implementation of the Android device listening on port 4000 and resolving the source address of the packet. MainActivity.kt(Android)

override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        receiverBroadcast()
    }

    fun receiverBroadcast(a) {
        Thread(Runnable {
            val buffer = ByteArray(25)
            val packet = DatagramPacket(buffer, buffer.size)
            val socket = DatagramSocket(4000)
            socket.soTimeout = 5000
            while (true) {
                try {
                    socket.receive(packet) // block reception
                    val msg = String(packet.data)
                    if (packet.data! =null && msg.contains("this is nodejs server")) {
                        val ip = packet.address.hostAddress
                        Log.i(tag, "ReceiverBroadcast >>>>>>>> Obtained the server IP address =${ip},msg=${msg}")
                        break}}catch (e: SocketTimeoutException) {  // The receiving timeout is abnormal
                    Log.i(tag, "startReceiver>>>>>>>> timeout")
                    break
                }
            }
        }).start()
    }
Copy the code

Since listening on the network port is intended to block the thread, a thread is opened to hold the implementation.

val buffer = ByteArray(25)
val packet = DatagramPacket(buffer, buffer.size)
Copy the code

Initializes a packet and gives a 25-byte byte array to receive the packet.

val socket = DatagramSocket(4000)
socket.soTimeout = 5000
Copy the code

Listen to port 4000 of itself and set timeout period for 5s. After enabling blocking listening for 5s, exceptions will be thrown.

socket.receive(packet)
Copy the code

Start blocking listening, and the monitored data will be put into packet.

val msg = String(packet.data)
if (packet.data! =null && msg.contains("this is nodejs server")) {
	val ip = packet.address.hostAddress
}
Copy the code

If you can go to the next step, it means that the port received the data, and then judge whether there is a good “password” agreed with the server in the data, if there is, you can directly get the source address of the data, that is, the server address we want. If not, keep listening.

The whole process is not very simple, let’s comb through it again:

  • The server sends broadcast packets.
  • The client listens on the corresponding port;
  • If the target field is discovered, the packet is parsed and the IP address is obtained.

Scheme V2.0 – multicast implementation

Plan 1 is a solution to my problem, but only enough. After reading the introduction of multicast and broadcasting in section 1, you will surely agree that multicast is more appropriate in the questions raised in this article. I think so too, so let’s see how that works. The point of multicast is that devices in multicast need to join multicast groups before they can send and receive data, and apis are available in network programming libraries on all platforms. The use of multicast is almost the same as broadcast, except that you need to enter a multicast group before sending and receiving a message. SendBroad.js(NodeJs)

const dgram = require("dgram");
const server = dgram.createSocket("udp4");

const message = Buffer.from("this is nodejs server"."ascii");

server.bind(1234.function () {
  server.addMembership("224.0.0.114");
});

const interval = setInterval(
  () = > {
    if (i > 5) {
      console.log("End multicast");
      server.close();
      clearInterval(interval);
    } else {
      server.send(message, 1234."224.0.0.114");
      console.log('Multicast data No.${i++}`); }},1000,(i = 0));
Copy the code

The difference with broadcast code is that you first have to join a multicast group.

server.bind(1234.function () {
  server.addMembership("224.0.0.114");
});
Copy the code

Then send a packet to the multicast address. The Android client also needs to join the multicast group before receiving the message.

fun receiverMulticast(a){
        Thread(Runnable {
            val buffer = ByteArray(25)
            val packet = DatagramPacket(buffer, buffer.size)
            val address= Inet4Address.getByName("224.0.0.114")
            val socket = MulticastSocket(1234)
            socket.joinGroup(address)
            socket.soTimeout = 50000
            while (true) {
                try {
                    socket.receive(packet) // block reception
                    val msg = String(packet.data)
                    if (packet.data! =null && msg.contains("this is nodejs server")) {
                        val ip = packet.address.hostAddress
                        Log.i(tag, "ReceiverMulticast >>>>>>>> Obtained the server IP address =${ip},msg=${msg}")
                        break}}catch (e: SocketTimeoutException) {  // The receiving timeout is abnormal
                    Log.i(tag, "receiverMulticast>>>>>>>> timeout")
                    break
                }
            }
        }).start()
    }
Copy the code

The difference is these three lines of code:

val address= Inet4Address.getByName("224.0.0.114")  // Multicast group address
val socket = MulticastSocket(1234) // Configure the listening port
socket.joinGroup(address) // Join the multicast group
Copy the code

Extension – Universal network discovery protocol

Below the application layer, the server is just a device. There are many device discovery protocols, such as mDNS, Bonjour, DNS-SD, DDPS, etc., but these protocols have a specific implementation based on multicast.

mDNS

Android system built-in services, with registration, discovery and parsing functions.

Bonjour

IOS, Android mDNS from this.

DDPS

The above protocol is very troublesome when cross-platform, may not find a complete library, need to implement their own. DDPS protocol is derived from THE DLNA protocol of UPuP(plug and play) technology (used for TV screen casting), and there are a lot of information.