Android Tutorial Android Network Tutorial

Status
Not open for further replies.
This is an old tutorial. All new implementations of network solutions should be based on AsyncStreams.

The Network library allows you to communicate over TCP/IP with other computers or devices.
The Network library contains two objects. Socket and ServerSocket.
The Socket object is the communication endpoint. Reading and writing are done with Socket.InputStream and Socket.OutputStream.

ServerSocket is an object that listens for incoming connections. Once a connection is established an event is raised and a socket object is passed to the event sub. This socket will be used to handle the new client.

Client application
Steps required:
- Create and initialize a Socket object.
- Call Socket.Connect with the server address.
- Connection is done in the background. The Connected event is raised when the connection is ready or if it failed.
- Communicate with the other machine using Socket.InputStream to read data and Socket.OutputStream to write data.

Server application
Steps required:
- Create and initialize a ServerSocket object.
- Call ServerSocket.Listen to listen for incoming connections. This happens in the background.
- Once a connection is established the NewConnection event is raised and a Socket object is passes.
- Call ServerSocket.Listen if you want to accept more connections.
- Using the Socket object received, communicate with the client.

We will see two examples.
The first example connects to a time server and displays the current date and time as received from the server.

B4X:
Sub Process_Globals
    Dim Socket1 As Socket
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    Socket1.Initialize("Socket1")
    Socket1.Connect("nist1-ny.ustiming.org" , 13, 20000)
End Sub

Sub Socket1_Connected (Successful As Boolean)
    If Successful = False Then
        Msgbox(LastException.Message, "Error connecting")
        Return
    End If
    Dim tr As TextReader
    tr.Initialize(Socket1.InputStream)
    Dim sb As StringBuilder
    sb.Initialize
    sb.Append(tr.ReadLine) 'read at least one line
    Do While tr.Ready
        sb.Append(CRLF).Append(tr.ReadLine)
    Loop
    Msgbox("Time received: " & CRLF & sb.ToString, "")
    Socket1.Close
End Sub
We are creating a new socket and trying to connect to the server which is listening on port 13.
The next step is to wait for the Connected event.
If the connection is successful we create a TextReader object and initialize it with Socket1.InputStream. In this case we want to read characters and not bytes so a TextReader is used.
Calling tr.ReadLine may block. However we want to read at least a single line so it is fine.
Then we read all the other available lines (tr.Ready means that there is data in the buffer).

network_1.png


In the second application we will create a file transfer application, that will copy files from the desktop to the device.
The device will use a ServerSocket to listen to incoming connections.
Once a connection has been made, we will enable a timer. This timer checks every 200ms whether there is any data waiting to be read.

The file is sent in a specific protocol. First the file name is sent and then the actual file.
We are using a RandomAccessFile object to convert the bytes read to numeric values. RandomAccessFile can work with files or arrays of bytes, we are using the later in this case.
RandomAccessFile can be set to use little endian byte order. This is important here as the desktop uses this byte order as well.

The desktop example application was written with Basic4ppc.
Once connected the user selects a file and the file is sent to the device which saves it under /sdcard/android.
Both applications are attached.

Some notes about the code:
- The server is set to listen on port 2222.
The server displays its IP when it starts. The desktop client should use this IP address when connecting to a real device (this IP will not work with the emulator).
However if you work with the emulator or if your device is connected to the computer in debug mode you can use 'adb' to forward a desktop localhost port to the device.
This is done by issuing "adb forward tcp:5007 tcp:2222"
Now in the client code we should connect to the localhost ip with port 5007.
B4X:
Client.Connect("127.0.0.1", 5007)
Again if you are testing this application in the emulator you must first run this adb command. Adb is part of the Android SDK.

- Listening to connections:
B4X:
Sub Activity_Resume
        ServerSocket1.Listen
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then
        Timer1.Enabled = False
        Socket1.Close
        ServerSocket1.Close 'stop listening
    End If
End Sub

Sub ServerSocket1_NewConnection (Successful As Boolean, NewSocket As Socket)
    If Successful Then
        Socket1 = NewSocket
        Timer1.Enabled = True
        InputStream1 = Socket1.InputStream
        OutputStream1 = Socket1.OutputStream
        ToastMessageShow("Connected", True)
    Else
        Msgbox(LastException.Message, "Error connecting")
    End If
    ServerSocket1.Listen 'Continue listening to new incoming connections
End Sub
In Sub Activity_Resume (which also called right after Activity_Create) we call ServerSocket.Listen and start listening to connections. Note that you can call this method multiple times safely.
In Sub Activity_Pause we close the active connection (if there is such a connection) and also stop listening. This only happens if the user pressed on the back key (UserClosed = True).
The ServerSocket will later be initialized in Activity_Create.

The server side application can handle new connections. It will just replace the previous connection with the new one.
The desktop client example application doesn't handle broken connections. You will need to restart it to reconnect.

Edit: It is recommended to use the new AsnycStreams object instead of polling the available bytes parameter with a timer. Using AsyncStreams is simpler and more reliable.
 

Attachments

  • NetworkExample.zip
    23.7 KB · Views: 7,732
Last edited:

Reinosoft

Member
Licensed User
Longtime User
use of Textreader with TCP Socket

Hello,

i've got some problems using textreader with Sdkversion 10 or above
(i removed this from the manifest editor) --> android:targetSdkVersion="14"
now the TCP socket receives data.

if i'm using an Sdkversion >=10, i've got an exception.

is there a solution? i've tried an Asyncstream; but then my battery is empty within 4 hours.

I rather want to use the textreader, with a timer, so every 6 seconds it checks for waiting data. (which (i've checked) using less battery power)

B4X:
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
   Dim IsConnected As Boolean
   
   Dim Pollings_Gemist As Int 'Aantal keren dat de heartbeat gemist is
   Dim TCP_LastReceiveData As Long 'Tijd dat de laatste heartbeat is binnengekomen
   
   Dim RestartServiceTime As Long 
   Dim ServiceTimeout = 300000 '5 minutes
   
   Dim myTimer As Timer

   Dim Password As String
   
   Dim WriteText As  TextWriter
   Dim txtReceive As TextReader

   Dim Socket1 As Socket

End Sub
Sub myTimer_Tick
   Dim Received As String   
   Dim NowTimer As Long = DateTime.Now 
   Dim CleanStr As String
   
   Try

      
      
      If txtReceive.Ready = True Then 'Data is waiting!
         Pollings_Gemist = 0

         Received = ModSecurity.Hex2Text(txtReceive.ReadLine )
         CleanStr = ModSecurity.Crypt(Received,Password)
         
         TCP_LastReceiveData = NowTimer + 30000
         Select Case CleanStr
            Case "BELL"
               PlayMP3("deurbel.mp3")
                              
            Case "NOOP"
            Case Else
               
         End Select
      
      End If
         
   Catch
      Log("Error")
   End Try

   Log("timer")
   CheckTimeOut
   CheckRestartService
End Sub
Sub CheckRestartService
   'Sets a delay for the restart of the service
   Dim NowTimer As Long = DateTime.Now 

   If NowTimer > RestartServiceTime Then
      StartServiceAt("", NowTimer + RestartServiceTime + 10000,True)
      RestartServiceTime  = NowTimer + RestartServiceTime
   End If

End Sub

'<SOCKET>
Sub Socket1_Connected (Successful As Boolean)
   Try
      If Successful = True Then
         Log("connected = true")
         IsConnected = True
         txtReceive.Initialize(Socket1.InputStream)
         WriteText.Initialize(Socket1.OutputStream)
      End If
      
   Catch
      Log("connecting Error")
   End Try
End Sub
Sub SendTCPData(Text As String) As Boolean
   Dim RawText As String
   
   Try
      RawText = ModSecurity.Crypt(Text,Password)
      WriteText.WriteLine (ModSecurity.Text2Hex(RawText))
      WriteText.Flush 
      Return True
   Catch
   
   End Try
End Sub

Sub RestartTcpClient
   Dim NowTimer As Long = DateTime.Now 

   IsConnected = False
   
   Try
      TCP_LastReceiveData= NowTimer + 30000
      Log("Restart TCP Client")
      Socket1.Initialize("Socket1")
      Socket1.Connect("xx.xx.xxx.xxx",899,20000)
   Catch
      Log("TCP Client Error")
   End Try
End Sub

Sub CheckTimeOut
   If DateTime.Now > TCP_LastReceiveData Then 'Timeout opgetreden
      
      Pollings_Gemist = Pollings_Gemist + 1
      RestartTcpClient
      
      If Pollings_Gemist > 2 Then
         Pollings_Gemist = 0
         PlayMP3("connectionerror.mp3")
      End If
   End If

End Sub
'</SOCKET>

'<SERVICE>
Sub Service_Create

End Sub
Sub Service_Start (StartingIntent As Intent)
   Dim Phone As PhoneWakeState 
   Dim Notif As Notification    

   Phone.PartialLock 

   Notif.Initialize
   Notif.Icon = Null
   Notif.SetInfo("Reinosoft","", Main) 
   Notif.Sound=False
   Notif.Vibrate=True
   Notif.Light=False
   Notif.AutoCancel=True
   
   RestartTcpClient

   myTimer.Initialize("myTimer",6000)
   myTimer.Enabled = True
   
   Service.StartForeground(1,Notif)

End Sub
Sub Service_Destroy
   PlayMP3("slowhoop.mp3")
End Sub
'</SERVICE>
 

Reinosoft

Member
Licensed User
Longtime User
Error Message

I've got a "android.os.NetworkOnMainThreadException"
if you can't recreate it i could send you the whole source.
 
Last edited:

basic4usager

New Member
Licensed User
Longtime User
Communicate with TTL to WIFI module

HI:

I have a transparent TTl to WIFI module who act as server in my local network.

When I use a TCP Terminal on my android viewpad it work well. It s possible to send carracter and receive it.

But When I use this program, It s does'nt connect with This error "Transport endpoint is not connected"

I Try with a TCP server on my PC and it s the same it work with TCP terminal but not with this program.

I will appraciate any help.

(Sorry for my english it s not my first language)

Thanks

There is the code based on Erel code


Sub Process_Globals
Dim Socket1 As Socket
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
'Do not forget to load the layout file created with the visual designer. For example:
'Activity.LoadLayout("Layout1")
Socket1.Initialize("Socket1")
'Socket1.Connect("nist1-ny.ustiming.org" , 13, 20000) 'It s connect
'Socket1.Connect("64.90.182.55",13,2000) 'It s connect
'Socket1.Connect("192.168.1.122",8080,2000) 'Pc as server
Socket1.Connect("192.168.1.128",8080,2000) 'Wifi module

End Sub
Sub Activity_Resume

End Sub
Sub Activity_Pause (UserClosed As Boolean)

End Sub
Sub Socket1_Connected (Successful As Boolean)
If Successful = False Then
Msgbox(LastException.Message, "Error connecting")
Return
Else
Msgbox("Connected","Status")
End If

Dim tr As TextReader
tr.Initialize(Socket1.InputStream)
Dim sb As StringBuilder
sb.Initialize
sb.Append(tr.ReadLine) 'read at least one line
Do While tr.Ready
sb.Append(CRLF).Append(tr.ReadLine)
Loop
Msgbox("Time received: " & CRLF & sb.ToString, "")
Socket1.Close
End Sub
 
Last edited:

basic4usager

New Member
Licensed User
Longtime User
Communicate with TTL to WIFI module Is working now

Hi

It s working now. I'm not shure what made the difference, but it is working now.

Any way, thanks a lots
 

maleche

Active Member
Licensed User
Longtime User
32767
I have device that communicates on port 35000. Can this port number be used if the Port is INT (max 32767)?
Thanks
 

JUAN CARLOSORDOÑEZ

Member
Licensed User
Longtime User
Erel:

This somehow can help me to take the sqlite database from the server (pc) and not from my tablet like now.

example:

DbFileDir = "// 192.168.1.1/example"
sqlparametros.Initialize (DBFileDir, "inventdroid.db", True)

My App run perfectly but write the data in my Tablet, now i need that do it to the pc (server)

How can i do it? is there some library?

Thank You !!
 

JUAN CARLOSORDOÑEZ

Member
Licensed User
Longtime User
I don't understand the reason for your answer. I know it is not a forum for private help. I just ask for those who want and can respond. I wrote "Erel" because you publish the tutorial. My question still here. please!! Thanks
 

Victor jung

Member
Licensed User
Longtime User
Hello,
I am trying to send as simple text to a netcat server to try basic things, but I receive nothing.
Here is my code:
B4X:
Sub Process_Globals
    Dim Socket1 As Socket
        Dim tw As TextWriter
End Sub

Sub Globals

    Private Button1 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("main")
    Socket1.Initialize("Socket1")
    Log("try to connect")
    Socket1.Connect("192.168.1.57" , 21, 20000)
End Sub

Sub Socket1_Connected (Successful As Boolean)
    If Successful = False Then
        Msgbox(LastException.Message, "Error connecting")
        Return
    End If
    Msgbox ("connected!", "OH YES")
    tw.Initialize(Socket1.OutputStream)
End Sub
Sub Button1_Click
    tw.Write("blabla")
    Log("write")
End Sub

It's pretty simple, but still I never receive "blabla" on my netcat server when I push the button, I just got the "write" log...
Any ideas why? Is my use of the textWriter good? this is my biggest doubt.

Ps:
If I use the time example, I can receive text sent from the netcat server.
Thanks for the help.
 
Last edited:

Victor jung

Member
Licensed User
Longtime User
I ended by using asyncstream after all cause the frustration was to big. But could you explain why? I guess network used to work before asyncstream was available.
Also you used textWriter and reader in your example.
Thanks a lot.
Victor jung
 

deantangNYP

Active Member
Licensed User
Longtime User
2 question:
1) May i know how a server socket can establish connection with a known client IP address and Port?

something like...
socket.connect(Client IP Address, Port, timeout)

2) Can server socket establish connection with multiple clients sharing the same Port?


B4X:
Sub Server1_NewConnection (Successful As Boolean, NewSocket As Socket)
    If Successful Then
        ToastMessageShow("Connected_Client01", False)
        Socket1 = NewSocket
        'AStreams1.InitializePrefix(Socket1.InputStream, False, Socket1.OutputStream, "AStreams1")
        AStreams1.Initialize(Socket1.InputStream, Socket1.OutputStream, "AStreams1")
    Else
        ToastMessageShow(LastException.Message, True)
    End If
    Server1.Listen

'This is to show the IP ADDRESS of the connected client
    Dim r As Reflector
   r.Target = NewSocket
   r.Target = r.GetField("socket")
   r.Target = r.RunMethod("getInetAddress") 'InetAddress
   Dim ip As String = r.RunMethod("getHostAddress")
   ToastMessageShow (ip,False)

End Sub

'Send message to client
Sub btn_Click
    If AStreams1.IsInitialized = False Then Return
    If edt.Text.Length > 0 Then
        Dim buffer() As Byte
        buffer = edt.Text.GetBytes("UTF8")
        AStreams2.Write(buffer)
        edt.SelectAll
        Log("Sending: " & edt.Text)
    End If
End Sub
 
Last edited:
Status
Not open for further replies.
Top