B4A Library Network library v1.10 - UDP supported

Status
Not open for further replies.

Rusty

Well-Known Member
Licensed User
Longtime User
Erel thanks for all your help. I don't know how you can respond to everyone's questions and still develop such a great product.
I came up with some PC-VB code that starts a separate thread to monitor UDP broadcast datagrams and thought someone might benefit:
B4X:
Imports System
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets
...
    Public UDPPort As Integer = 4444
    Public ReceivingUdpClient As UdpClient
    Public RemoteIpEndPoint As New System.Net.IPEndPoint(System.Net.IPAddress.Any, 0)
    Public ThreadReceive As System.Threading.Thread

    Private udpSendMsg As Byte() = New Byte() {}
    Private udpClient As New UdpClient
...

Sub Start
        localAddr = GetLocalIpAddress()

        'UDP

        If ReceivingUdpClient IsNot Nothing Then
            ReceivingUdpClient.Close()
        End If
        ReceivingUdpClient = New UdpClient(UDPPort)          'open a UDP port
        ReceivingUdpClient.EnableBroadcast = True
        'SendUDPMessages()
        ThreadReceive = New Thread(AddressOf ReceiveUDPMessages)        'start a thread to handle UDP i/o
        ThreadReceive.Start()
    End Sub
    
    ''' <summary>
    ''' Receive UDP broadcast message 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ReceiveUDPMessages()
        Try
            Dim receiveBytes As [Byte]() = receivingUdpClient.Receive(RemoteIpEndPoint)
            NewClient = RemoteIpEndPoint.Address.ToString
            Dim Data As BitArray
            Data = New BitArray(receiveBytes)
            Dim strReturnData As String = BytesToString(receiveBytes)
            LOG("Receiving UDP msg: " & strReturnData)
            SendUDPMessage(ClientIP(index).Address, "UDP msg from host: " & localAddr.ToString & " " & Port.ToString)
            ReceiveUDPMessages()            'recursive call
        Catch ex As Exception
        End Try
    End Sub

    ''' <summary>
    ''' Send UPD Message directly to an IP address/port
    ''' </summary>
    ''' <param name="IPaddr"></param>
    ''' <param name="Msg"></param>
    ''' <remarks></remarks>
    Public Sub SendUDPMessage(ByVal IPaddr As IPAddress, ByVal Msg As String)
        LOG("info", "Sending: " & Msg)
        udpClient.Connect(IPaddr, UDPPort)
        udpSendMsg = StrToByteArray(Msg)
        udpClient.Send(udpSendMsg, udpSendMsg.Length) 'send a broadcast message
    End Sub
From the tablet:
B4X:
MANIFEST CONTENTS:

'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<supports-screens android:largeScreens="true" 
    android ....

A UDP SERVICE: - requires NET library, REFLECTION library, PHONE library
#Region Module Attributes
    #StartAtBoot: False
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim UDPSocket1 As UDPSocket   
    Dim Tablet As Reflector
    Dim Device As Phone
    Dim ServerIndex As Int = -1
    Dim RequestIP As Boolean = True
    Dim UDPPort As Int = 4444
End Sub

Sub Service_Create
    Tablet.Target = Tablet.GetContext
    Tablet.Target = Tablet.RunMethod2("getSystemService", "wifi", "java.lang.String")
    Tablet.Target = Tablet.RunMethod2("createMulticastLock", "mylock", "java.lang.String")
    Tablet.RunMethod2("setReferenceCounted", False, "java.lang.boolean")     'not really necessary but safer
    Tablet.RunMethod("acquire")                                            'acquire the lock
    UDPSocket1.Initialize("UDP", UDPPort, 128)    'Port and buffer size can be changed
    ToastMessageShow("Port " & UDPPort & " initialized.",True)
End Sub

Sub Service_Start (StartingIntent As Intent)
    SendMYID
End Sub

Sub SendMYID
    If RequestIP = True Then
        RequestIP = False
        UDPSendMsg("UDP Msg from Tablet ", "255.255.255.255")
    End If
End Sub

'send the host a UDP message
Sub UDPSendMsg(msg As String, IPAddr As String)
Log("        Sending: " & msg)
    Dim Packet As UDPPacket
    Dim data() As Byte  
    data = msg.GetBytes("UTF8")
    Packet.Initialize(data, IPAddr, UDPPort)    'IP and Port can be changed
    UDPSocket1.Send(Packet)
End Sub

'Host requested our info
Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Dim IP As String = Packet.HostAddress
Log("        Receiving: " & msg)
    StopService("")            'terminate the UDP if you don't need it anymore
End Sub

Sub Service_Destroy
    UDPSocket1.Close
    Tablet.RunMethod("release")                        ' release when not needed to save battery    
End Sub

I hope this helps someone.
BTW, if you run the tablet code on multiple Android devices, they will communicate via the router, not exactly peer-to-peer, but it works.
Regards,
Rusty
 
Last edited:

EduardoElias

Well-Known Member
Licensed User
Longtime User
Rusty,

Can I use this code to implement a way to auto discovery of a device on the local wireless network?

I have a server that my b4a app comunicate with, implemented as a http server for webservices.

it is delphi language, but i could adapt to use the concept of your pc-vb code.

I am not experienced with protocols this level. What I need that somehow the server broadcast a signal, that the tablets on the same network recognize it and indentify from wich ip it comes from, then it will be used to connect using http for the webservices.

Can you give me some directions?

Many Thanks

Eduardo Elias
 

Rusty

Well-Known Member
Licensed User
Longtime User
Yes.
What I do is:
  1. On the PC I have a program that listens on a specific port
    B4X:
     Case "UDPR:                   'UDP request from tablet, they want our IP address"
                            Dim pRet As Integer
                            Try
                                udpClient.Connect(IPAddress.Parse("255.255.255.255"), Port)
                                udpSendMsg = StrToByteArray("UDPS:")
                                pRet = udpClient.Send(udpSendMsg, udpSendMsg.Length)
                              
                            Catch ex As Exception
                                MsgBox("Couldn't communicate UDP IP address")
                            End Try
    Where PORT is previously agreed; where the UDPS: is a text message from the tablet that just says, tell me your IP/port (I made that up); where the UDPCLIENT.SEND is defined as
B4X:
Private udpSendMsg As Byte() = New Byte() {}
Private udpClient As New UdpClient
  1. On the tablet my program sends a broadcast datagram to ANY listening device (includes other tablets as well)
    B4X:
    Sub Process_Globals
        'These global variables will be declared once when the application starts.
        'These variables can be accessed from all modules.
        Dim UDPSocket1 As UDPSocket   
        Dim Tablet As Reflector
        Dim Device As Phone
        Dim ServerIndex As Int = -1
        Dim RequestIP As Boolean = True
        Dim UDPPort As Int = 4444
    End Sub
    
    Sub Service_Create
        Tablet.Target = Tablet.GetContext
        Tablet.Target = Tablet.RunMethod2("getSystemService", "wifi", "java.lang.String")
        Tablet.Target = Tablet.RunMethod2("createMulticastLock", "mylock", "java.lang.String")
        Tablet.RunMethod2("setReferenceCounted", False, "java.lang.boolean")     'not really necessary but safer
        Tablet.RunMethod("acquire")                                            'acquire the lock
        UDPSocket1.Initialize("UDP", UDPPort, 128)    'Port and buffer size can be changed
    '    ToastMessageShow("Port " & UDPPort & " initialized.",True)
    End Sub
    
    Sub Service_Start (StartingIntent As Intent)
        SendMYID
    End Sub
    
    Sub SendMYID
        If RequestIP = True Then
            RequestIP = False
            UDPSendMsg("MYID:~" & ServerIndex & "~" & Main.version.SerialNo & "~" & Main.LicenseData.GroupCode & "~" & _
                        Main.CS.FacilityID & " " & Main.licensedata.Addr1 & " " & Main.LicenseData.City & ", " & Main.LicenseData.state, "255.255.255.255")
        End If
    End Sub
    
    'send the host a UDP message
    Sub UDPSendMsg(msg As String, IPAddr As String)
    Log("        Sending: " & msg)
        Dim Packet As UDPPacket
        Dim data() As Byte  
        data = msg.GetBytes("UTF8")
        Packet.Initialize(data, IPAddr, UDPPort)    'IP and Port can be changed
        UDPSocket1.Send(Packet)
    End Sub
    
    'Host requested our info
    Sub UDP_PacketArrived (Packet As UDPPacket)
        Dim msg As String
        msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
        Dim IP As String = Packet.HostAddress
        Dim parts() As String = Regex.Split("~", msg)
        If parts.Length >= 3 Then
            Select Case parts(0)
                Case "UDPS:"                    'this is a legitimate "here is my ip/port" request from server
    Fn.Logit("        Receiving: " & msg)
                    Main.TCP.IPAddress = parts(2)
                    Main.TCP.Port = parts(3)
                    XMLBuilder.SaveIPProfile
                    StopService("")
                Case "UDPR:"
    Fn.Logit("        Receiving: " & msg)
                    Main.TCP.IPAddress = parts(2)
                    Main.TCP.Port = parts(3)
                    XMLBuilder.SaveIPProfile
                    ServerIndex = parts(1)
                    SendMYID
                    StopService("")
            Case Else                            'other broadcast datagram, don't terminate
            End Select
        End If
    End Sub
    
    Sub Service_Destroy
        UDPSocket1.Close
        Tablet.RunMethod("release")                        ' release when not needed to save battery    
    End Sub
  2. when the PC receives the broadcast datagram it responds with a formatted message giving its IP address and port.
I hope this helps.
Rusty
 

EduardoElias

Well-Known Member
Licensed User
Longtime User
Rusty,

I want to thank you for this code.

I made the changes needed to my software and worked very well. I have now my apk broadcasting a message that the server listens to, and getting the answer it discover the server ip. Based on that I can easily setup my apk on local networks.

That is a great improvement for my application. I thank you a lot!

Eduardo Elias
 

ericvanderhoeven

Member
Licensed User
Longtime User

Hi,

I tried the sample code from an other snippet =


B4X:
Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        UDPSocket1.Initialize("UDP", 5000, 8000)
    End If
    Activity.LoadLayout("udp")
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Msgbox("Message received: " & msg, "")
End Sub
Sub ButtonSend_Click
    Dim Packet As UDPPacket
    Dim data() As Byte
    data = Edit.text.GetBytes("UTF8")
    Packet.Initialize(data, "192.168.178.2", 5000)
    UDPSocket1.Send(Packet)
    ToastMessageShow("Message send = " &Edit.Text, False)
End Sub

I get ... well... nothing... Both devices are connected via Local Wifi access point that acts as DHCP server in the range 192.168.178.xxx

Forgot to add a permission in the manifest?
Anything I'm doing wrong?
Could the access point be blocking UDP packages internally?

Any help is appreciated!

Thanks,

Eric
 

ericvanderhoeven

Member
Licensed User
Longtime User
Hi Erel,

thanks for coming to my rescue. I am using network v1.24, IDE 2.70. I have no clue what does not work as there is nothing extraordinary in the log file. Ticking off the log filter reveals some network activity but also non critical.

The funny thing is that e.g. UPD chat (https://play.google.com/store/apps/details?id=com.teledhil.chatBroadcast)
does work straight out of the box, on the same wifi network. Be it that it misses quite some chats going back and forth between devices, irrespective of their class (also on e.g. a Samsung Note). By that, I'm guessing UPD messages are one-off's and aren't buffered. Miss it and it's gone?

Having said that, UPD chat works (depending on device, somewhere between 10 and 40% drop rate). My code yields 0% success rate

Thanks,

Eric
 

ericvanderhoeven

Member
Licensed User
Longtime User
IP address?

WHY is that relevant? I thought UDP does not require an explicit TCPIP socket? It is the primary reason for me to use UDP, to stay away from that. I only need to broadcast messages for everybody in the same LAN segment.

I am testing this on an Access point that acts as a DHCP server (it being 192.168.1.1) and serves wifi clients in the 192.168.1.xxx range. The tablets log on with IP's such as 192.168.1.8 and 9

I picked 192.168.1.2 as I figured it may be best for it not to be the DHCP server? The IP address is a label identifying the sender correct?

And how to know which port is ''available'' for UDP? I know a little bit about the protocol table in c:\windows\system32\drivers\etc and port 5000 (on there..) seems to be free..

Thanks,

Eric
 

ericvanderhoeven

Member
Licensed User
Longtime User
To add to this,

I am a bit puzzled, in the case of UDP messaging, whether one actually need to set up a server/central deposit/host to bounce messages through/to?

I am currently under the assumption that UDP messages just distribute themselves through the (W)LAN and the sender/receiver are irrelevant. Therefore I interpret the code to be independent of assigning any host/target at all. Perhaps I am just completely wrong there.

When I look at the definitions of the network modules UDPSocket and UDPPacket there seems to be quite some indications of a host and a target.

Could that be the reason the message just fly around the place and never reach a host/destination?

Thanks,

Eric
 

ericvanderhoeven

Member
Licensed User
Longtime User
Thanks Erel!

I was half way towards getting the concept. This was the final push and it works like a gem.

Here is the ENTIRE code for those wanting an out-of-the-box solution/code =

B4X:
Sub Process_Globals
    Dim UDPSocket1 As UDPSocket
    Dim Server As ServerSocket
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim ButtonSend As Button
    Dim EditData As EditText
    Dim EditDest As EditText
    Dim LabelIP As Label
End Sub
Sub Activity_Create(FirstTime As Boolean)
    Dim IP As String
    If FirstTime Then
        UDPSocket1.Initialize("UDP", 5000, 8000)
        IP = Server.GetMyWifiIP
    End If
    Activity.LoadLayout("udp")
    LabelIP.Text = IP
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Msgbox("Message received: " & msg, "")
End Sub
Sub ButtonSend_Click
    Dim Packet As UDPPacket
    Dim dest As String
    Dim data() As Byte
    data = EditData.text.GetBytes("UTF8")
    dest = EditDest.text
    Packet.Initialize(data, dest, 5000)
    UDPSocket1.Send(Packet)
    ToastMessageShow("Message send = " &EditData.Text, False)
End Sub

When you start the app, it shows its current IP address on the WLAN. All you need to enter to send a message to this device from any of the other devices in the same WLAN that are running the same app, is the message (duhhh) and its IP. The attached files are in a RAR renamed to ZIP.

Thanks,

Eric
 

Attachments

  • UDP.zip
    316.6 KB · Views: 571

freedom2000

Well-Known Member
Licensed User
Longtime User
Thanks Erel!

I was half way towards getting the concept. This was the final push and it works like a gem.

Here is the ENTIRE code for those wanting an out-of-the-box solution/code =

Eric

@ericvanderhoeven , many thanks for sharing this code

It works like a charm.
Here is the counterpart for PC under Vb.net.

I have tested both this prog and your app, they are fully compatible

So everything is fine between my Pc and my Nexus when connected over wifi.

What I wanted to do is to hook my PC on my nexus acting as a wifi hotspot.
So I turned on the connection sharing and hooked the PC on it
Fine, internet was there !

I modded your app to catch not the WifiIP but the current IP
B4X:
IP = Server.GetMyIP

And I could send a message from the PC to the Android

But I cannot send message from the Android to the PC, despite the fact that I changed the PC IPadress accordingly to what gave ipconfig on my old DOS command windows...

Any idea why ?
 

Attachments

  • UDP_test.zip
    14.8 KB · Views: 410

eynysman

New Member
Licensed User
Longtime User
hello

do not speak English, have little programming experience and ask for help

I'm doing a custom wifi network manager

I took example of how to connect on a wifi network and could

to disconnect I'm having problems

I am using the following example


Dim mywifi As VBConnect

Dim Wifi1 As WiFiConnect


Sub WiFiAdd_Click

Wifi1.connectToSSID(Wifi1.WIFI_WPA, “SSID1”, “123456789”)

End Sub


Sub WiFidisconnect_Click

mywifi.RemoveAllSavedNetworks ‘remove all saved networks End Sub


the doubt is, how to disconnect only one specific network, example: "Wifi1. disconnectToSSID ("SSID1") just unplugging "SSID1" network

Hold and thank you in advance

Eynysman Felix Pacheco

Cabo Frio – Rio de Janeiro - Brasil
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…