Android Question TCP CLient

rscheel

Well-Known Member
Licensed User
Longtime User
I have an application in android studio, which makes a connection to an ip and a specific port, this can send data, and is constantly receiving a response JSON, the messages that I can send the same are JSON type, I want to implement it with B4A, someone who is handling this issue that can guide me.

B4X:
this.client = new TCPClient(this.mHandler, "192.168.1.1", 23000, this.mValueChanged, this.mStateChanged, this.mNewWeightCallback, this.mButtonChanged);
 

rscheel

Well-Known Member
Licensed User
Longtime User
You need to use Socket from Network library with AsyncStreams. The AsyncStreams tutorial is important as well as this example: [B4X] Network + AsyncStreams + B4XSerializator

B4XSerializator is not relevant in your case.


@Erel I modified your example a bit to send text, I can send text perfectly, but I do not receive anything in, it does not run AStream_NewText


Main

B4X:
Sub Process_Globals
    'Type MyMessage (Name As String, Age As Int, Image() As Byte)
    'Type MyMessage (JSon As String)
End Sub

Sub Globals
    Private edtIp As FloatLabeledEditText
    Private lblMyIp As Label
    Private btnConnect As Button
    Private lblStatus As Label
    Private edtAge As FloatLabeledEditText
    Private edtName As FloatLabeledEditText
    Private btnSend As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    edtIp.EditText.ForceDoneButton = True
    edtAge.EditText.InputType = edtAge.EditText.INPUT_TYPE_NUMBERS
    edtAge.Text = 10
    edtIp.Text = "192.168.0.108"
    edtName.Text = "Blady"
End Sub

Sub Activity_Resume
    SetState
End Sub

Public Sub SetState
    btnSend.Enabled = Starter.connected
    If Starter.connected Then
        btnConnect.Text = "Disconnect"
        lblStatus.Text = "Connected"
    Else
        btnConnect.Text = "Connect"
        lblStatus.Text = "Disconnected"
    End If
    lblMyIp.Text = "My ip: " & Starter.server.GetMyWifiIP
End Sub

Sub btnSend_Click
    CallSub2(Starter, "SendData", "Prueba")
End Sub

Sub btnConnect_Click
    If Starter.connected = False Then
        If edtIp.Text.Length = 0 Then
            ToastMessageShow("Please enter the server ip address.", True)
            Return
        Else
            CallSub2(Starter, "ConnectToServer", edtIp.Text)
        End If
    Else
        CallSub(Starter, "Disconnect")
    End If
End Sub

Public Sub NewText (data As String)
    Log("Entro Aqui")
    edtName.Text = data 'BytesToString(data,0,data.Length,"UTF-8")
End Sub

Sub pnlDrawing_Touch (Action As Int, X As Float, Y As Float)
    cvs.DrawCircle(X, Y, 30dip, Rnd(0xFF000000, -1), True, 0)
    pnlDrawing.Invalidate 
End Sub


Starter

B4X:
Sub Process_Globals
    Public connected As Boolean
    Private client As Socket
    Public server As ServerSocket
    Private astream As AsyncStreamsText
    Private const PORT As Int = 23000
    Private working As Boolean = True
End Sub

Sub Service_Create
    server.Initialize(PORT, "server")
    ListenForConnections
End Sub

Private Sub ListenForConnections
    Do While working
        server.Listen
        Wait For Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        If Successful Then
            CloseExistingConnection
            client = NewSocket
            'If astream.IsInitialized Then astream.Close
            astream.Initialize(Me, "astream", NewSocket.InputStream, NewSocket.OutputStream)
            UpdateState(True)
        End If
    Loop
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Public Sub ConnectToServer(Host As String)
    Log("Trying to connect to: " & Host)
    CloseExistingConnection
    Dim client As Socket
    client.Initialize("client")
    client.Connect(Host, PORT, 10000)
    Wait For Client_Connected (Successful As Boolean)
    If Successful Then
        'astream.InitializePrefix(client.InputStream, False, client.OutputStream, "astream")
        astream.Initialize(Me,"astream", client.InputStream, client.OutputStream)
        UpdateState (True)
    Else
        Log("Failed to connect: " & LastException)
    End If
End Sub

Public Sub Disconnect
    CloseExistingConnection
End Sub

Sub CloseExistingConnection
    If astream.IsInitialized Then astream.Close
    If client.IsInitialized Then client.Close
    UpdateState (False)
End Sub

Sub UpdateState (NewState As Boolean)
    connected = NewState
    CallSub(Main, "SetState")
End Sub

Sub AStream_Error
    UpdateState(False)
End Sub

Sub AStream_Terminated
    UpdateState(False)
End Sub

Sub AStream_NewText (Buffer As String)
    Log("NewData")
    CallSub2(Main, "NewText", Buffer)
End Sub

Public Sub SendData (data As String)
    Log("Envia Dato")
    'Log(BytesToString(data,0,data.Length, "UTF-8"))
    If connected Then astream.Write(data)
End Sub


'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
There is no NewText callback for astream. It should be NewData. Try this:

B4X:
Sub astream_NewData (Buffer() As Byte)
    Private msg As String = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
   
    Log("NewData")
    CallSub2(Main, "NewText", msg)
End Sub

- Colin
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
Also - I think when you get your NewData working, you'll find that you need to convert your string to bytes when you send it:
B4X:
Public Sub SendData (data As String)
    Log("Envia Dato") 
 
    If connected Then 
        Private buffer() as byte = data.GetBytes("UTF8")
        astream.Write(buffer)
    End If
End Sub

- Colin.
 
Upvote 0

rscheel

Well-Known Member
Licensed User
Longtime User
Also - I think when you get your NewData working, you'll find that you need to convert your string to bytes when you send it:
B4X:
Public Sub SendData (data As String)
    Log("Envia Dato")

    If connected Then
        Private buffer() as byte = data.GetBytes("UTF8")
        astream.Write(buffer)
    End If
End Sub

- Colin.

In sending I have no problem send what I need, but I can not receive the message I send back that is a text. if I send it in Byte it sends anything but a text.

I've tried what you tell me but it does not work
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
In sending I have no problem send what I need, but I can not receive the message I send back that is a text. if I send it in Byte it sends anything but a text.

I've tried what you tell me but it does not work
Can you post your code for the changes you made to the AStream_NewText sub?

- Colin.
 
Upvote 0

rscheel

Well-Known Member
Licensed User
Longtime User
Main

B4X:
Sub Globals
    Private edtIp As FloatLabeledEditText
    Private lblMyIp As Label
    Private btnConnect As Button
    Private lblStatus As Label
    Private edtAge As FloatLabeledEditText
    Private edtName As FloatLabeledEditText
    Private btnSend As Button
    Private cvs As Canvas
    Private pnlDrawing As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    cvs.Initialize(pnlDrawing)
    edtIp.EditText.ForceDoneButton = True
    edtAge.EditText.InputType = edtAge.EditText.INPUT_TYPE_NUMBERS
    edtAge.Text = 10
    edtIp.Text = "192.168.0.108"
    edtName.Text = "Blady"
End Sub

Sub Activity_Resume
    SetState
End Sub

Public Sub SetState
    btnSend.Enabled = Starter.connected
    If Starter.connected Then
        btnConnect.Text = "Disconnect"
        lblStatus.Text = "Connected"
    Else
        btnConnect.Text = "Connect"
        lblStatus.Text = "Disconnected"
    End If
    lblMyIp.Text = "My ip: " & Starter.server.GetMyWifiIP
End Sub

Sub btnSend_Click
    CallSub2(Starter, "SendData", "{CMD:48,P1:0,P2:0}")
End Sub

Sub btnConnect_Click
    If Starter.connected = False Then
        If edtIp.Text.Length = 0 Then
            ToastMessageShow("Please enter the server ip address.", True)
            Return
        Else
            CallSub2(Starter, "ConnectToServer", edtIp.Text)
        End If
    Else
        CallSub(Starter, "Disconnect")
    End If
End Sub

Public Sub NewText (data As String)
    Log("Entro Aqui")
    edtName.Text = data 'BytesToString(data,0,data.Length,"UTF-8")
End Sub



Starter

B4X:
Sub Process_Globals
    Public connected As Boolean
    Private client As Socket
    Public server As ServerSocket
    Private astream As AsyncStreamsText
    Private const PORT As Int = 23000
    Private working As Boolean = True
End Sub

Sub Service_Create
    server.Initialize(PORT, "server")
    ListenForConnections
End Sub

Private Sub ListenForConnections
    Do While working
        server.Listen
        Wait For Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        If Successful Then
            CloseExistingConnection
            client = NewSocket
            'If astream.IsInitialized Then astream.Close
            astream.Initialize(Me, "astream", NewSocket.InputStream, NewSocket.OutputStream)
            UpdateState(True)
        End If
    Loop
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Public Sub ConnectToServer(Host As String)
    Log("Trying to connect to: " & Host)
    CloseExistingConnection
    Dim client As Socket
    client.Initialize("client")
    client.Connect(Host, PORT, 10000)
    Wait For Client_Connected (Successful As Boolean)
    If Successful Then
        'astream.InitializePrefix(client.InputStream, False, client.OutputStream, "astream")
        astream.Initialize(Me,"astream", client.InputStream, client.OutputStream)
        UpdateState (True)
    Else
        Log("Failed to connect: " & LastException)
    End If
End Sub

Public Sub Disconnect
    CloseExistingConnection
End Sub

Sub CloseExistingConnection
    If astream.IsInitialized Then astream.Close
    If client.IsInitialized Then client.Close
    UpdateState (False)
End Sub

Sub UpdateState (NewState As Boolean)
    connected = NewState
    CallSub(Main, "SetState")
End Sub

Sub AStream_Error
    UpdateState(False)
End Sub

Sub AStream_Terminated
    UpdateState(False)
End Sub

Sub AStream_NewText (Buffer As String)
    Log("NewData")
    CallSub2(Main, "NewText", Buffer)
End Sub

Public Sub SendData (data As String)
    Log("Envia Dato")
    'Log(BytesToString(data,0,data.Length, "UTF-8"))
    If connected Then astream.Write(data)
End Sub


'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
In sending I have no problem send what I need, but I can not receive the message I send back that is a text.

If you can't receive messages, how do you know that it's sending correctly?

- Colin.
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
B4X:
Sub AStream_NewText (Buffer AsString)
    Log("NewData")
    CallSub2(Main, "NewText", Buffer)
End Sub

This is wrong. There is no AStream_NewText callback. Re-read my first reply & change the name of the callback to astream_NewData.

- Colin.
 
Upvote 0

rscheel

Well-Known Member
Licensed User
Longtime User
because I'm seeing it with Hercules.

Captura.PNG
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
Is it possible Hercules is intercepting the message & it's not getting to the callback? Have you tried running it without Hercules running?

- Colin.
 
Upvote 0

rscheel

Well-Known Member
Licensed User
Longtime User
AsyncStreamsText collects the received text until it finds an end of line character. Make sure to add such character when you send messages.

I tried with what you indicate but could not walk.
 
Upvote 0

rscheel

Well-Known Member
Licensed User
Longtime User
I have modified the AsyncStreamsText sub, modifying the terminator by "}", now it works, as I can make it not delete "}", which will keep it at the end.

B4X:
Private Sub astreams_NewData (Buffer() As Byte)
    Dim newDataStart As Int = sb.Length
    sb.Append(BytesToString(Buffer, 0, Buffer.Length, charset))
    Dim s As String = sb.ToString
    Dim start As Int = 0
    For i = newDataStart To s.Length - 1
        Dim c As Char = s.CharAt(i)
            If i = 0 And c = "}" Then '\n...
            start = 1 'might be a broken end of line character
            Continue
        End If
        If c = "}" Then '\n
            CallSubDelayed2(mTarget, mEventName & "_NewText", s.SubString2(start, i))
            start = i + 1
        Else If c = "}" Then '\r
            CallSubDelayed2(mTarget, mEventName & "_NewText", s.SubString2(start, i))
            If i < s.Length - 1 And s.CharAt(i + 1) = "}" Then '\r\n
                i = i + 1
            End If
            start = i + 1
        End If
    Next
    If start > 0 Then sb.Remove(0, start)
End Sub
 
Upvote 0
Top