B4A Library Network library v1.10 - UDP supported

Discussion in 'Additional libraries, classes and official updates' started by Erel, May 11, 2011.

Thread Status:
Not open for further replies.
  1. Erel

    Erel Administrator Staff Member Licensed User

    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
     

    Attached Files:

  2. joedarock

    joedarock Member Licensed 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
     
  3. Erel

    Erel Administrator Staff Member Licensed 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:
    Code:
    @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.
     
  4. ehansoft

    ehansoft New Member

    help me

    I want to test the UDP but can not download
     
  5. Erel

    Erel Administrator Staff Member Licensed User

  6. csjoe72

    csjoe72 Member Licensed 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
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    Most mobile internet providers block such traffic. I don't believe that you will be able to send UDP packets directly between two devices over the internet.
     
  8. csjoe72

    csjoe72 Member Licensed 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
     
  9. csjoe72

    csjoe72 Member Licensed User

    (I work in one internet provider :D )
     
  10. peacemaker

    peacemaker Well-Known Member Licensed 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 ?
     
  11. Jim

    Jim Member Licensed 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.
     
  12. peacemaker

    peacemaker Well-Known Member Licensed 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: Oct 14, 2011
  13. Jim

    Jim Member Licensed User

    Given a serversocket listening on emulator 5554, have emulator 5556 connect to 10.0.2.2 on port 18789
     
  14. Jim

    Jim Member Licensed User

    Use GetMyIP on real devices, but in this instance use 10.0.2.2 for the emulator
     
  15. peacemaker

    peacemaker Well-Known Member Licensed 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: Oct 15, 2011
  16. peacemaker

    peacemaker Well-Known Member Licensed 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.
     
  17. Jim

    Jim Member Licensed 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.
     
  18. Jim

    Jim Member Licensed 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.
     
  19. peacemaker

    peacemaker Well-Known Member Licensed User

    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.
     
  20. Jim

    Jim Member Licensed User

    Quick and dirty. Hope this helps.

    [​IMG]

    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.
     

    Attached Files:

    Last edited: Oct 20, 2011
Thread Status:
Not open for further replies.
Loading...