Android Question Failed upload a file to a FTP server

amorosik

Well-Known Member
Licensed User
I have a client on an Android app which, on command, sends files to an ftp server on a pc built in B4J
The server on the pc is always active
If I start the Android app and try to send everything works correctly
After a few minutes that the app is waiting, if I start the same command to send files to the ftp server, the command fails From log B4A it appears:

Error uploading file - android.system.ErrnoException: sendto failed: EPIPE (Broken pipe) or
Error uploading file - java.net.SocketTimeoutException

What can I check to eliminate the disconnection problem after a few minutes?
(B4A 10.70 + jdk-11.0.1, Win 10 pro 64bit, B4J 9.10 + jdk-11.0.1)

CODE FOR B4J SERVER:
Masterdir = "C:\FTP"
server.Initialize(Me, "FTPServer")
server.SetPorts(Ftp_Control_Port, Ftp_Data_Port1, Ftp_Data_Port2)
server.AddUser(Utente, Password,Dir_utente)
server.ForcedServerIp = ""
server.BaseDir = Masterdir
server.Start

CODE FOR B4A CLIENT:
Sub Process_Globals
    Dim FtpCli As FTP
    End Sub

Public Sub Inizializza
    FtpCli.Initialize("FtpCliEvent", Main.ftp_server_ip,Main.ftp_server_port,Main.ftp_user,Main.ftp_password)
    FtpCli.PassiveMode = True
    FtpCli.UseSSL = False
    FtpCli.UseSSLExplicit = False
    End Sub
 
Sub FtpUploadFile(dir_file_da_inviare As String, file_da_inviare As String)
    Dim sf As Object = FtpCli.UploadFile(dir_file_da_inviare, file_da_inviare, True, "/" & file_da_inviare)
    Wait For (sf) FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        Log("File was uploaded successfully -> " & file_da_inviare)
        Else
        Log("Error uploading file - " & LastException.Message)
        End If
    End Sub
 
Sub FtpCliEvent_UploadProgress (ServerPath As String, TotalUploaded As Long, Total As Long)
    Dim s As String= "UP " & ServerPath & "  " & Round(TotalUploaded / 1000) & "KB "
    If Total > 0 Then s = s & " out of " & Round(Total / 1000) & "KB"
    Log(s)
    End Sub

Sub FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    Log(ServerPath & ", Success=" & Success)
    If Success = False Then Log(LastException.Message)
    End Sub
 
Last edited:

amorosik

Well-Known Member
Licensed User
Did you try setting:
B4X:
FtpCli.TimeoutMs = 5 * 60 * 1000 ' 5 minutes

If 5 minutes are not enough, I think you have to initialize again FtpCli.

Ok, but the problem remain after 5 min
How to check if connection is active, and eventually reconnect, before start every ftp communications?
 
Upvote 0

LucaMs

Expert
Licensed User
Ok, but the problem remain after 5 min
How to check if connection is active, and eventually reconnect, before start every ftp communications?
I don't see such a property nor a method that is raised when the connection is lost.

I would try setting the TimeoutMs to 5 minutes and using a timer, whose Interval I would set to 5 minus - N seconds, and in the Tick event I would reinitialize the ftp.
Disable and enable again the timer, in the event Tick.
 
Last edited:
Upvote 0

amorosik

Well-Known Member
Licensed User
I don't see such a property nor a method that is raised when the connection is lost.

I would try setting the TimeoutMs to 5 minutes and using a timer, whose Interval I would set to 5 minus - N seconds, and in the Tick event I would reinitialize the ftp.
Disable and enable again the timer, in the event Tick.

It is not possible to re-initialize the connection
There may be data transmissions in progress
 
Upvote 0

José J. Aguilar

Expert
Licensed User
I'm not on my PC right now, but if I remember, you should ask If FtpCli.isInitialized before start uploading. If not, then initialize it again
 
Upvote 0

José J. Aguilar

Expert
Licensed User
BTW, you're using the Wait For for the upload, right?

B4X:
Wait For (sf) ftp_UploadCompleted (ServerPath As String, Success As Boolean)

Probably you should close the connection (FtpCli.close will wait until the uploads ends if there's still any active) and initialize it again when you want to upload another file.
 
Upvote 0

LucaMs

Expert
Licensed User
BTW, you're using the Wait For for the upload, right?

B4X:
Wait For (sf) ftp_UploadCompleted (ServerPath As String, Success As Boolean)

Probably you should close the connection (FtpCli.close will wait until the uploads ends if there's still any active) and initialize it again when you want to upload another file.
That's another good option.
 
Upvote 0

amorosik

Well-Known Member
Licensed User
Now I start the initialization code for each file sent, not just once when the program is opened
I have modified as well as code below
And it seems to go

B4X:
Public Sub Inizializza
    End Sub
   
Sub FtpUploadFile(dir_file_da_inviare As String, file_da_inviare As String)
    Try
        FtpCli.Close
        Catch
        Log(LastException)
        End Try
   
    FtpCli.Initialize("FtpCliEvent", Main.ftp_server_ip,Main.ftp_server_port,Main.ftp_user,Main.ftp_password)
    FtpCli.PassiveMode = True
    FtpCli.UseSSL = False
    FtpCli.UseSSLExplicit = False
    FtpCli.TimeoutMs=5*60*1000  ' 5 min
   
    Dim sf As Object = FtpCli.UploadFile(dir_file_da_inviare, file_da_inviare, True, "/" & file_da_inviare)
    Wait For (sf) FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        Log("File was uploaded successfully -> " & file_da_inviare)
        FtpCli.Close
        Else
        Log("Error uploading file - " & LastException.Message)
        End If
   
    End Sub
 
Upvote 0

amorosik

Well-Known Member
Licensed User
With the current procedure there is no longer the problem of disconnection even after a long time
However, I realized that not all the files for which the upload to the PC was requested are actually sent
For example, if I am uploading some photos and these are 100 in the Androd memory, then on the pc I find 90 of them
I thought that the 10 unsent had some problem, but if I try to send only those 10 they arrive correctly on my pc
I think the problem is that the FTP upload command is sent (from the PC to the phone) faster than the phone can send the files and therefore when I sent all 100 commands to download the 100 files, the phone it has reached the tenth and is continuing
I assumed it might be the ftp server, and I used Filezilla instead of my B4J ftp server, but the problem remains
So I think it is highly likely that the anomaly is in the Android code
I also thought that for some files the transmission was not completed correctly and I therefore inserted a breakpoint to the line
Log ("Error uploading file -" & LastException.Message)
but at that point the code never passes

For this I would ask for your help to understand what could be wrong with the routine I use to send


B4X:
#Region  Service Attributes 
    #StartAtBoot: False
#End Region

Sub Process_Globals
   Dim FtpCli As FTP
   End Sub

Sub Service_Create
   End Sub

Sub Service_Start (StartingIntent As Intent)
    Service.StopAutomaticForeground 'Call this when the background task completes (if there is one)
    End Sub

Sub Service_Destroy
   End Sub

Sub FtpUploadFile(dir_file_da_inviare As String, file_da_inviare As String)
    Try
        FtpCli.Close
        Catch
        Log(LastException)
        End Try
    
    FtpCli.Initialize("FtpCliEvent", Main.ftp_server_ip,Main.ftp_server_port,Main.ftp_user,Main.ftp_password)
    FtpCli.PassiveMode = False
    FtpCli.UseSSL = False
    FtpCli.UseSSLExplicit = False
    FtpCli.TimeoutMs=60*60*1000  ' 60 minuti
    
    Dim sf As Object = FtpCli.UploadFile(dir_file_da_inviare, file_da_inviare, True, "/" & file_da_inviare)
    Wait For (sf) FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
        Log("File was uploaded successfully -> " & file_da_inviare)
        Else
        Log("Error uploading file - " & LastException.Message)
        End If
End Sub

Sub FtpCliEvent_UploadProgress (ServerPath As String, TotalUploaded As Long, Total As Long)
    End Sub

Sub FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    Log(ServerPath & ", Success=" & Success)
    If Success = False Then Log(LastException.Message)
    End Sub
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
If FtpUploadFile is called before the previous file was uploaded then it will be broken. Uploading 100 files requires managing a queue.

You add files to the queue and you have a different sub that monitors the queue and uploads the files. You can use KeyValueStore to manage the queue so it will be persistent.

B4X:
Sub HandleQueue
Do While True
   Sleep(1000)
    If Queue.Size = 0 Then Contine
   Dim NextFileToUpload As CustomType = Queue.Get(0)
   'upload
  
Wait For (sf) FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
     Queue.RemoteAt(0)

   End If
   kvs.Put("queue", Queue)
Loop
End Sub
 
Upvote 0

José J. Aguilar

Expert
Licensed User
FtpCli.PassiveMode = False


So, are you calling FtpUploadFile from the same sub itself?
 
Upvote 0

amorosik

Well-Known Member
Licensed User

So, are you calling FtpUploadFile from the same sub itself?

Yes, i know
But for Filezilla it need PassiveMode to 'true'

"..So, are you calling FtpUploadFile from the same sub itself?.."
No, where did you see it?
 
Upvote 0

José J. Aguilar

Expert
Licensed User
No, where did you see it?
Ups, sorry... I'm wrong, I looked at the code too quick

1630305609934.png
 
Upvote 0

amorosik

Well-Known Member
Licensed User
....If FtpUploadFile is called before the previous file was uploaded then it will be broken....

Ah, I thought you could run more commands in sequence even without waiting for the upload end
So the problem is this, thank you very much
 
Upvote 0

amorosik

Well-Known Member
Licensed User
You add files to the queue and you have a different sub that monitors the queue and uploads the files. You can use KeyValueStore to manage the queue so it will be persistent.

B4X:
Sub HandleQueue
Do While True
   Sleep(1000)
    If Queue.Size = 0 Then Contine
   Dim NextFileToUpload As CustomType = Queue.Get(0)
   'upload

Wait For (sf) FtpCliEvent_UploadCompleted (ServerPath As String, Success As Boolean)
    If Success Then
     Queue.RemoteAt(0)

   End If
   kvs.Put("queue", Queue)
Loop
End Sub

You're talking about Queue, but what exactly do you mean?
Is it a standard structure available, like a list or map, or do you need some special library to use it?
Searching on the forum I find this module for B4R
Is that what you're talking about?
 
Upvote 0

José J. Aguilar

Expert
Licensed User
You're talking about Queue, but what exactly do you mean?
I think his idea is to have for example a list (call it 'queue'), with all the names of the files you want to upload (or a CustomType with names and other data if you need it, size, type, ....)
Then you get every file to upload from this "queue", if the file is uploaded successfully, then you remove it from the list (is a typo RemoteAt instead of RemoveAt?) and loop until the 'queue' is empty.
 
Upvote 0

amorosik

Well-Known Member
Licensed User
I think his idea is to have for example a list (call it 'queue'), with all the names of the files you want to upload (or a CustomType with names and other data if you need it, size, type, ....)
Then you get every file to upload from this "queue", if the file is uploaded successfully, then you remove it from the list (is a typo RemoteAt instead of RemoveAt?) and loop until the 'queue' is empty.

A List, ok
I try, thank you
 
Upvote 0
Top