B4A Library Network library v1.10 - UDP supported

Status
Not open for further replies.
The network library was updated and it now supports UDP communication (as well as TCP).
A simple example is included in the documentation: Basic4android - Network

Installation instructions:
- Unzip the attached file.
- Copy both files to the internal libraries folder: C:\Program Files\Anywhere Software\Basic4android\Libraries
 

Attachments

  • Network.zip
    12.2 KB · Views: 2,110

joedarock

Member
Licensed User
Longtime User
Thanks Erel!

Interestingly, just yesterday I began to educate myself in library development so I could build this one. I did get as far as building the jar and xml files, but nothing close to anything that was useful. You came along with this at just the right time for me to move on with my UDP application! I do want to learn to make my own libraries though.

I have a question: In my work, I was attempting to use the java.net DatagramSocket classes. Was I on the right track?

Thanks again!

Joe
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
This library is not so simple. The receive method of DatagramSocket is blocking waiting for data. This means that a secondary thread is needed to handle the receiving data.

Here is the code of the two objects:
B4X:
    @ShortName("UDPSocket")
    @Permissions(values = {"android.permission.INTERNET"})
    @Events(values={"PacketArrived (Packet As UDPPacket)"})
    public static class UDPSocket {
        private UDPReader reader;
        private DatagramSocket ds;
        /**
         * Initializes the socket and starts listening for packets.
         *EventName - The name of the Sub that will handle the events.
         *Port - Local port to listen on. Passing 0 will cause the OS to choose an available port automatically.
         *ReceiveBufferSize - The size of the receiving packet. Packets larger than this value will be truncated.
         *Pass 0 if you do not want to receive any packets.
         */
        public void Initialize(BA ba, String EventName, int Port, int ReceiveBufferSize) throws SocketException {
            Close();
            if (Port == 0)
                ds = new DatagramSocket();
            else
                ds = new DatagramSocket(Port);
            if (ReceiveBufferSize > 0) {
                reader = new UDPReader();
                reader.working = true;
                reader.socket = ds;
                reader.receiveLength = ReceiveBufferSize;
                reader.ba = ba;
                reader.eventName = EventName.toLowerCase(BA.cul);
                Thread t = new Thread(reader);
                t.setDaemon(true);
                t.start();
            }
        }
        /**
         * Tests whether this object is initialized.
         */
        public boolean IsInitialized() {
            return ds != null && !ds.isClosed();
        }
        /**
         * Gets the local port that this socket listens to.
         */
        public int getPort() {
            return ds.getLocalPort();
        }
        /**
         * Sends a Packet.
         */
        public void Send(DatagramPacket Packet) throws IOException {
            ds.send(Packet);
        }
        
        /**
         * Closes the socket.
         */
        public void Close() {
            if (ds != null)
                ds.close();
            if (reader != null)
                reader.working = false;
            reader = null;
            ds = null;
        }
        @Override
        public String toString() {
            if (ds == null)
                return "Not initialized";
            return "Port=" + getPort();
        }
        private static class UDPReader implements Runnable {
            volatile boolean working;
            DatagramSocket socket;
            int receiveLength;
            BA ba;
            String eventName;
            @Override
            public void run() {
                while (working) {
                    try {
                        DatagramPacket p = new DatagramPacket(new byte[receiveLength], receiveLength);
                        socket.receive(p);
                        UDPPacket u = new UDPPacket();
                        u.setObject(p);
                        ba.raiseEventFromDifferentThread(null, null, 0, eventName + "_packetarrived", false, new Object[] {u});
                    } catch (IOException e) {
                        e.printStackTrace();
                        if (working) {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                            }
                        }
                    }
                }
            }
        }
        /**
         * A packet of data that is being sent or received.
         *To send a packet call one of the Initialize methods and then send the packet by passing it to UDPSocket.Send.
         *When a packet arrives you can get the data in the packet from the available properties.
         */
        @ShortName("UDPPacket")
        public static class UDPPacket extends AbsObjectWrapper<DatagramPacket> {
            /**
             * Initializes the packet and makes it ready for sending.
             *Data - The data that will be send.
             *Host - The target host name or IP address.
             *Port - The target port.
             */
            public void Initialize(byte[] Data, String Host, int Port) throws SocketException {
                Initialize2(Data, 0, Data.length, Host, Port);
            }
            /**
             * Similar to Initialize. The data sent is based on the Offset and Length values.
             */
            public void Initialize2(byte[] Data, int Offset, int Length, String Host, int Port) throws SocketException {
                DatagramPacket d = new DatagramPacket(Data, Offset, Length, new InetSocketAddress(Host, Port));
                setObject(d);
            }
            /**
             * Gets the length of available bytes in the data. This can be shorter than the array length.
             */
            public int getLength() {
                return getObject().getLength();
            }
            /**
             * Gets the data array received.
             */
            public byte[] getData() {
                return getObject().getData();
            }
            /**
             * Gets the offset in the data array where the available data starts.
             */
            public int getOffset() {
                return getObject().getOffset();
            }
            /**
             * Gets the port of the sending machine.
             */
            public int getPort() {
                return getObject().getPort();
            }
            /**
             * Gets the host name or IP address of the sending machine.
             */
            public String getHost() {
                return getObject().getAddress().getHostName();
            }
            @Override
            public String toString() {
                if (getObjectOrNull() == null)
                    return super.toString();
                return "Length=" + getLength() + ", Offset=" + getOffset() + ", Host=" + getHost() + ", Port=" + getPort();
            }
        }
    }

Libraries developers: it is recommended to override the toString method. The debugger calls this method to show the debugging information.
 

csjoe72

Member
Licensed User
Longtime User
send udp packet over the internet

Hi Erel,

I can send UPD packet over local lan (wlan) between two Android devices. (it's my second day with B4A)
Now I would like to send UPD packet over internet (both directions).
I can send packets from the mobile phone (over internet) to my tablet (home network, with fix, public IP address) with port forwarding on my router.
But I can't send back packets to mobile phone, because my phone address and port always changes (mobile provider NAT/PAT) .

The incoming UDP packet include the source IP and port number of my mobile. If I know these I will be able to send back the packet over the internet. (I hope)
How can I read this informations from the incoming UDP packet?

Thanks, Joe
 

csjoe72

Member
Licensed User
Longtime User
Hi,

It's works!
If I send packet to home from my phone, I'm opening a new session. This session length is 20 sec.
I can capture the source address and port of this packet with wireshark at home, and if I edit the basic code to new destrination address and port, I will able to send back the new data to phone.

I did it.

Joe
 

peacemaker

Expert
Licensed User
Longtime User
How to test UDP transceiving only with 2-3 emulators ?
One emulator gets its sent text back - good. Another emulator does not get.
IPs are sure, the same :)
Possible ?
 

Jim

Member
Licensed User
Longtime User
The android emulator is accessible via telnet to pass commands through a command line interface. Telnet to localhost with the emulator's port number and you will be able to issue a port redirect from emulator1->emulator2. There are other helpful commands you can issue for app testing and development. Change battery status, etc.

Example of commands using windows standard telnet client (telnet.exe):
o localhost 5554
redir add tcp:7000:7000

Assuming you have 2 emulators running, named 5554 and 5555, a serversocket may run on 5554 listening on port 7000. Connect emulator 5555 to 10.0.2.2 on port 7000. The 2 emulators will be able to communicate.

You may change tcp to udp.
 

peacemaker

Expert
Licensed User
Longtime User
Thanks, Jim !
Redirect command made like:

adb -s emulator-5554 emu redir add udp:18789:18789
and
adb -s emulator-5555 emu redir add udp:18789:18789

But unclear about IP address.
Application uses in Packets the broadcastAddress = "255.255.255.255".

GetMyIP are both the same 10.0.2.15 in emulators.
How to manage IPs ?

I have read http://developer.android.com/guide/developing/devices/emulator.html#connecting about redirection and IP settings of Android, but again do not understand how to setup 2 instances of emulator for the same Peer-to-Peer UDP application :-(
 
Last edited:

Jim

Member
Licensed User
Longtime User
Given a serversocket listening on emulator 5554, have emulator 5556 connect to 10.0.2.2 on port 18789
 

Jim

Member
Licensed User
Longtime User
Use GetMyIP on real devices, but in this instance use 10.0.2.2 for the emulator
 

peacemaker

Expert
Licensed User
Longtime User
For Peer-to-Peer I use the single UDPSocket.
That sends UDPPacket of broadcastAddress = "255.255.255.255" to port 18789.
UDP has no Listen, sub PacketArrived gets its Packet well.

For UDP - no host IP to be used.
How to try to use "10.0.2.2" here ?

If to use it as address in UDPpacket - self-receiving stopped to work, and another emulator as before receives nothing.

It needs to test with real devices, but... i have just one...
 
Last edited:

peacemaker

Expert
Licensed User
Longtime User
Finally, i have made sure that my P2P code is working fully OK.
But it's found only by trying on 2 real devices :-(
Emulators do not work...at me.
 

Jim

Member
Licensed User
Longtime User
I don't have any experience using the UDP as I have only been working with TCP. I am unsure if this will work for you either, but it may be helpful. I am able to connect a real device to an emulator through TCP by port mapping the incoming real device to the localhost (which the emulator picks up the traffic).

The following port mapper is simple and gets the job done:
Network Downloads : PortMapper /// AnalogX

I have it configured to accept connections from 192.*.*.* (my LAN) and map them to the localhost and the port of the software (set through the redir add tcp: command)

Again, I have only used this with TCP however the portmapper allows mapping of UDP. Perhaps this will help. I am sure there is some sort of solution beyond using 2 physical devices, but obviously, thats the simplest.
 

Jim

Member
Licensed User
Longtime User
I am happy to report the aforementioned port mapping strategy does infact work with UDP. I added UDP to a TCP network application (tcp for setting the stage/state with information that needs to be reliably delivered, udp for the constant transmission of packets quickly for which I can stand a degree of packet loss). I was able to connect to the emulator from a physical device through both tcp and udp at the same time. I hope this helps you.
 

peacemaker

Expert
Licensed User
Longtime User
I am happy to report the aforementioned port mapping strategy does infact work with UDP you.

WOW ! Thank you fr this news !
But finally could you post here the setting you made ? Or screenshots ?
It'll be useful for many users, i'm sure.
 

Jim

Member
Licensed User
Longtime User
Quick and dirty. Hope this helps.

attachment.php


Edit: This is the procedure with the portmapper in the link I provided earlier. I chose this one for its simplicity, I am sure others exist and will work in a similiar fashion.
 

Attachments

  • portmapper.jpg
    portmapper.jpg
    61.8 KB · Views: 2,081
Last edited:
Status
Not open for further replies.
Top