Android Question 6 computers communicating via AsyncStreamsObject

Discussion in 'Android Questions' started by almontgreen, Jul 11, 2015.

  1. almontgreen

    almontgreen Active Member Licensed User

    I have an android X80h tablet and Tronsmart box communicating beautifully over a portable private hotspot running on the tablet using the brilliant AsyncStreamsObject library. Problem is, I need to talk to 4 more Tronsmart boxes from the tablet. I've read the forums and there are comments regarding adding sockets to do this but I don't know enough to understand. I looked at the CCTV examples and I'm still a bit lost.

    I'd hate to go blutooth... but that could be an option I suppose. :(
     
  2. Erel

    Erel Administrator Staff Member Licensed User

  3. almontgreen

    almontgreen Active Member Licensed User

    Ok, I will study cctv example harder! Sorry for 2nd post, wasn't sure 1st post actually posted. The support here is unsurpassed along with the patience of those willing to help people that are less accomplished trying to understand things. I am always surprised on the upside with what the tools from Anywhere Software can achieve and how rapidly things can happen. I'm not a "professional coder" by any measure, but I can make things work surprisingly well thanks to the tools and support available here.
     
    RandomCoder likes this.
  4. almontgreen

    almontgreen Active Member Licensed User

    Is it possible to have the server send info to the clients and have at least one client respond back to the server? I see where the clients get the server image with the Sub astream_NewData but I don't understand the reason to use AsyncStreamsObject vs. AsyncStreams ? So, can you have a server send info out to multiple clients and have at least one client respond? Before I start testing it would be useful to know if this is possible...
     
  5. Erel

    Erel Administrator Staff Member Licensed User

  6. almontgreen

    almontgreen Active Member Licensed User

    Thanks for pointing me in the right direction. First, I will try server sending to 2 clients, then I will try sending and receiving between server and two clients, then scale up to 4 clients. I assume from your answer that this is possible.
     
  7. almontgreen

    almontgreen Active Member Licensed User

    Ok, on a new connection I initialize a stream and start the stream input and output and write an object - then wait for a stream newObject response. I then close the stream and wait for a new connection and repeat. In this way I can communicate to several computers. I understand that much now. Apparently, you can't have more than one stream connected at any given time. Is that right? That was my takeaway from the cctv example. The issue with this approach is that an event happens only on the one computer that listens or acts as the server. The other computers have to keep trying to connect until successful and then close the connection as soon as possible so another computer can connect.

    Do I have this right?

    Code:
    Sub Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        
    If Successful Then
            
    If astreamO.IsInitialized Then astreamO.Close
            astreamO.Initialize(Me, 
    "astreamO")
            StartAstream(NewSocket)
       
    End If
    End Sub

    Sub StartAstream(s As Socket)
        astreamO.Start(s.InputStream, s.OutputStream)
        
    Dim p As StuffToSend
        p.info1 = 
    "a1"
        p.info2 = sf.Left(
    DateTime.Now,sf.Len(DateTime.Now)-1)
        p.info3 = 
    "z1"
        astreamO.WriteObject(
    "form", p)
    End Sub

    Sub astreamO_NewObject(Key As String, Value As Object)
        
    Select Key
    '       Case "simple value"
                Dim number As Int = Value
                
    ToastMessageShow("Close Connection" & number, False)
                astreamO.Close
       
    End Select
    End Sub
     
    Last edited: Jul 14, 2015
  8. Erel

    Erel Administrator Staff Member Licensed User

    You can keep all the streams open. There is no need to work with a single one at a time. See the CCTV example...
     
  9. almontgreen

    almontgreen Active Member Licensed User

    I am revisiting things after a break, and I've spent all day reading posts about using AsyncStreams, Sockets and multiple connections. I've stared at the B4J CCTV code and I don't understand how to handle multiple connections as it relates to trying to send and receive using AsyncStreamsObject with multiple sockets using more than one at a time.

    So far, I get that the place to start is with the Sub Server_NewConnection and putting each AsyncStream into a Type container. I don't understand what qualifies as "successful" because that doesn't seem to happen for more than one connection at a time. I love how the AsyncStreamsObject works but translating the individual AsyncStreams info from the B4J CCTV project into code that works with the AsyncStreamsObject for Android seems to be above my pay grade ;^)

    I am pretty stupid, but I don't think I'm the only one that doesn't understand working with a connection between more than two computers. A bit more info or tutorial would be incredibly helpful! I just upgraded to the new version of B4A and am blown away. I'm really struggling to understand how to keep track of multiple sockets and how the triggered events work. I thought about initializing multiple AsyncStreamsObject objects but that doesn't seem right?
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    Managing multiple connections is indeed not simple.

    It will be much simpler and more reliable to create a real server with B4J (not an Android app).

    I will try to explain this code:
    Code:
    Sub Server_NewConnection (Successful As Boolean, NewSocket As Socket)
       
    If Successful Then
         
    Dim astream As AsyncStreams
         astream.InitializePrefix(NewSocket.InputStream, 
    False, NewSocket.OutputStream, "astream")
         
    For Each li As LabelAndImageView In slots
           
    If li.connected = False Then
             li.connected = 
    True
             li.lbl.Text = 
    "Status: Connected"
             connections.Put(astream, li)
             
    Exit
           
    End If
         
    Next
       
    Else
         
    Log(LastException)
       
    End If
       
    server.Listen
    End Sub
    A new client has connected to the server so this event is raised.
    We create an AsyncStreams object that works with this socket.
    Now we need to store this AsyncStreams object. In this case the astream itself is used as the key and the value is an additional object which we will later use to show the image.

    Later when there is NewData available:
    Code:
    Sub astream_NewData (Buffer() As Byte)
    '   Log("received: " & DateTime.GetSecond(DateTime.Now))
       Dim In As InputStream
       
    In.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
       
    Dim img As Image
       img.Initialize2(
    In)
       
    Dim liiv As LabelAndImageView = connections.Get(Sender'<-- this is the interesting code
       liiv.iv.SetImage(img)
    End Sub
    We take the additional object from the Map and we set the received image to this object.

    In the CCTV example the server is not sending any information. If you need to send information to a specific client then you can use another Map that maps between the client id and the astream object.
     
    Matias Ferrer likes this.
  11. almontgreen

    almontgreen Active Member Licensed User

    Ok, so I've got something working on 3 tablets where two tablets send text to a server and the server then can send text to the two tablets. My code is terrible I'm sure, but it works! I'm starting to understand how this works and how it can be greatly simplified from what I have! Please take a look at the server side app. The last sub is a touch event that gets a swipe. I didn't use any layout as that makes it easier for me to understand and put the code into other projects. I am confused about what should go in the main and what should go somewhere else. I hope this helps somebody along with me! :eek:
    Code:
    #Region  Project Attributes 
        
    #ApplicationLabel: Server
        
    #VersionCode: 1
        
    #VersionName
        
    'SupportedOrientations possible values: unspecified, landscape or portrait.
        #SupportedOrientations: unspecified
        
    #CanInstallToExternalStorage: False
    #End Region

    #Region  Activity Attributes 
        
    #FullScreen: False
        
    #IncludeTitle: True
    #End Region

    Sub Process_Globals
        
    'These global variables will be declared once when the application starts.
        'These variables can be accessed from all modules.
        Private 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 connections As Map
        
    Dim Imageinfo1, Imageinfo2, Imageinfo3, Imageinfo4, Imageinfo5, Imageinfo6 As String
        
    Dim computer1, computer2, computer3, computer4, computer5, computer6 As String
        
    Dim slots As List
        
    Dim Panel1 As Panel
        
    Dim Canvas1 As Canvas
        
    Dim DestRect As Rect
        
    Dim n As Int
        
    Dim nz As Int
        
    Dim v_nbr As Int
        
    Dim nString As String
        
    Dim sf As StringFunctions
        
    Type LabelAndImageView (lbl As String, iv As String, connected As Boolean)
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
        n=
    0
        nz=
    0
        nString=
    " "
        slots.Initialize
        connections.Initialize
        computer1 = 
    "0"
        computer2 = 
    "0"
        computer3 = 
    "0"
        computer4 = 
    "0"
        computer5 = 
    "0"
        computer6 = 
    "0"
        slots.Add(CreateSlot(computer1, Imageinfo1))
        slots.Add(CreateSlot(computer2, Imageinfo2))
        slots.Add(CreateSlot(computer3, Imageinfo3))
        slots.Add(CreateSlot(computer4, Imageinfo4))
        slots.Add(CreateSlot(computer5, Imageinfo5))
        slots.Add(CreateSlot(computer6, Imageinfo6))
        
    server.Initialize(17178"server")
        
    server.Listen
       
        DestRect.Initialize(
    10901279517)
        Panel1.Initialize(
    "Panel1")
        
    Activity.AddView(Panel1,0,0Activity.Width, Activity.Height)
        Canvas1.Initialize(Panel1)
        Canvas1.DrawText(
    "My IP: " & server.GetMyIP,30dip,30dipTypeface.DEFAULT,20,Colors.white,"LEFT")
        Panel1.Invalidate
        
    Msgbox("ready","Alert")
    End Sub

    Sub Activity_Resume
        
    server.Listen
    End Sub

    Sub Activity_Pause (UserClosed As Boolean)
    Log("paused")
    End Sub

    Private Sub CreateSlot(lbl As String, iv As StringAs LabelAndImageView
        
    Dim liiv As LabelAndImageView
        liiv.Initialize
        liiv.iv = iv
        liiv.lbl = lbl
        liiv.connected = 
    False
        
    Return liiv
    End Sub

    Sub Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        nz=nz+
    1
        nString = 
    NumberFormat(nz, 00)&" Connection"
        
    If Successful Then
            
    Dim Astream As AsyncStreams
            Astream.InitializePrefix(NewSocket.InputStream, 
    False, NewSocket.OutputStream, "Astream")
            
    For Each li As LabelAndImageView In slots  'There are now 6 slots
                If li.connected = False Then
                    li.connected = 
    True
                    connections.Put(Astream, li)  
    'put info in map
                    'Log(li)
                    Canvas1.DrawText("██████████████████████████████████████████████████████████████████",20dip,50dipTypeface.DEFAULT,20,Colors.black,"LEFT")
                    Canvas1.DrawText(Astream,
    20dip,50dipTypeface.DEFAULT,20,Colors.white,"LEFT")
                    Panel1.Invalidate
                    
    Exit
                
    End If
            
    Next
        
    Else
            
    Log(LastException)
            Canvas1.DrawText(
    "████████████████████████",20dip,50dipTypeface.DEFAULT,20,Colors.black,"LEFT")
            Canvas1.DrawText(
    "Status: Connect Failed",20dip,50dipTypeface.DEFAULT,20,Colors.white,"LEFT")
            Panel1.Invalidate

        
    End If
        
    server.Listen
    End Sub

    Sub Astream_NewData (Buffer() As Byte)
        n=n+
    1
        nString=sf.Right(sf.left(connections.Get(
    Sender),6),1)
        
    Dim msg As String
        msg = 
    BytesToString(Buffer, 0, Buffer.Length, "UTF8")
            
    If nString<> sf.Right(sf.Left(msg,10),1Then
                n=
    1
                
    For Each li As LabelAndImageView In slots
                    
    If li.lbl=nString Then
                        li.lbl=sf.Right(sf.Left(msg,
    10),1)
                        
    Select True
                            
    Case n=1
                                computer1=sf.Right(sf.Left(msg,
    10),1)
                            
    Case n=2
                                computer2=sf.Right(sf.Left(msg,
    10),1)
                            
    Case n=3
                                computer3=sf.Right(sf.Left(msg,
    10),1)
                            
    Case n=4
                                computer4=sf.Right(sf.Left(msg,
    10),1)
                            
    Case n=5
                                computer5=sf.Right(sf.Left(msg,
    10),1)
                            
    Case n=6
                                computer6=sf.Right(sf.Left(msg,
    10),1)
                        
    End Select
                        
    Exit
                    
    End If
                    n=n+
    1
                
    Next
            
    End If
        Canvas1.DrawText(
    "██████████████████████████████████████████████████████████████████",20dip,70dipTypeface.DEFAULT,20,Colors.black,"LEFT")
        Canvas1.DrawText(nString&
    " "&msg,20dip,70dipTypeface.DEFAULT,20,Colors.white,"LEFT")
        Panel1.Invalidate
    End Sub

    Sub Send1(OutStr As String)
        
    Dim buffer() As Byte
        buffer = OutStr.GetBytes(
    "UTF8")
        
    Dim Astream As AsyncStreams = connections.GetKeyAt(sf.Val(computer2)-1'subtract 1 because it starts with 0
        Astream.Write(buffer)
    End Sub

    Sub Send2(OutStr As String)
        
    Dim buffer() As Byte
        buffer = OutStr.GetBytes(
    "UTF8")
        
    Dim Astream As AsyncStreams = connections.GetKeyAt(sf.Val(computer1)-1'subtract 1 because it starts with 0
        Astream.Write(buffer)
    End Sub

    Sub Send3(OutStr As String)
        
    Dim buffer() As Byte
        buffer = OutStr.GetBytes(
    "UTF8")
        
    Dim Astream As AsyncStreams = connections.GetKeyAt(sf.Val(computer3)-1'subtract 1 because it starts with 0
        Astream.Write(buffer)
    End Sub

    ' Add additional subs for up to 6 computers

    Sub Astream_Error
        
    Log("Error: " & LastException)
        
    Dim Astream As AsyncStreams = Sender
        ReleaseSlot(Astream)
        Astream.Close
    End Sub

    Private Sub ReleaseSlot(Astream As AsyncStreams)
        
    If connections.ContainsKey(Astream) Then
            
    Dim liiv As LabelAndImageView = connections.Get(Astream)
            liiv.connected = 
    False
            Canvas1.DrawText(
    "████████████████████████",20dip,50dipTypeface.DEFAULT,20,Colors.black,"LEFT")
            Canvas1.DrawText(
    "Status: Disconnected",20dip,50dipTypeface.DEFAULT,20,Colors.white,"LEFT")
            Panel1.Invalidate
            connections.Remove(Astream)
        
    End If
    End Sub

    Sub Astream_Terminated
        
    Dim Astream As AsyncStreams = Sender
        ReleaseSlot(Astream)
        Astream.Close
    End Sub

    Sub Panel1_Touch (Action As Int, X As Float, Y As Float)
        
    Select True
            
    Case Action = 0
                v_nbr = X
            
    Case Action = 2
               
            
    Case Action = 1
                
    Select True
                    
    Case v_nbr< (X-60)
                        Send1(
    "Right")
                    
    Case v_nbr> (X+60)
                        Send2(
    "Left")
                
    End Select
        
    End Select
    End Sub
     
Loading...