B4A Library [B4X] FTP Server implemented with Socket and AsyncStreams

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User

(Note that the FTP client above is not part of this solution. It only demonstrates how you can use a standard FTP client to communicate with the server.)

This is an example of using low level network features to implement a high level protocol.
It is an implementation of a standard FTP server. You can use standard FTP client programs to send or receive files.
As it is based on AsyncStreams and it can handle multiple concurrent connections.
It is compatible with B4J, B4i and B4A.
Note that only passive mode (which is the preferred method) is implemented.

It is a good example of using classes to handle multiple clients.
The solution is made of three classes:
FTPServer - There is a single instance of this class. It manages the server socket that listens on the control port (main port).
It also manages the connected clients and assigns a data port for each client.

FTPClient
- There is an instance of this class for each active connection. It uses AsyncStreamsText class to read the clients text commands. It creates a new FTPDataConnection instance for each task that requires communication over the data socket (upload, download and list files).

FTPDataConnection - An instance is created for each data task. It sends or receives the data and then closes the connection. Note that a new method was added to AsyncStreams that allows closing the channel after the data was sent (SendAllAndClose). Clients expect the data socket to be closed after the data is sent. There isn't any other cue that tells the client that all data was sent.

Not all commands are implemented. The common feature are supported: upload, download, delete, rename, list and others.

In B4A and B4J, JavaObject is used to call a native API that gets the canonical path and verify that the path is inside the set directory. There is no equivalent API in iOS. It is less important as each app is sandboxed anyway.

Using the server is simple:
B4X:
server.Initialize(Main, "FTPServer")
server.SetPorts(51041, 51042, 51142)
server.AddUser("Test", "test") 'user name and password.
server.BaseDir = File.DirRootExternal
server.Start
SetPorts - Sets the control port and the range of available data ports. When running on a non-mobile device, you need to make sure that the firewall allows incoming connections on all these ports.
AddUser - Adds a user name and password. You can call it multiple times.
BaseDir - Sets the client root folder.

In B4i you also need to stop the server when the application moves to the background and start it again when it resumes.

Implementing an FTP server that properly supports multiple clients is not a simple task. The code itself is not too complicated and is a good example for anyone who is working with network sockets.




Updates

V1.10 - Implemented as a cross platform b4xlib. Fixes an issue with uploading of small files. Adds support for UTF8 files and folders names.

The B4X_FTPServer projects are examples. FTPServer.b4xlib is the library itself.
 

Attachments

Last edited:

coslad

Well-Known Member
Licensed User
How to change the server adress from WIFI to Ethernet .
I have an adroid box tv, i use it as a sever , it has an ethernet connection and the wifi is off , the server's example uses the wifi connection , some suggest how to switch to ethernet ?
 

coslad

Well-Known Member
Licensed User
You are right, it listens even at Ethernet port, instead b4a bridge not does it, my mistake borned from that.
 

TomDuncan

Active Member
Licensed User
Have setup an FtpServer and all works ok (in release mode, not debug mode)
If I use Filezilla transfers are fine.
However, my ip-camera will not work.
I have it working using a Filezilla Server.
Here is the log files for an image transfer..

B4X:
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> Connected, sending welcome message...
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> 220-FileZilla Server version 0.9.41 beta
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> 220-written by Tim Kosse (Tim.Kosse@gmx.de)
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> 220 Please visit http://sourceforge.net/projects/filezilla/
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> USER point
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> 331 Password required for point
(000105)4/05/2017 13:38:23 PM - (not logged in) (10.1.1.20)> PASS ********
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 230 Logged on
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> TYPE I
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 200 Type set to I
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> CWD /20170504/images/
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 250 CWD successful. "/20170504/images" is current directory.
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> PASV
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 227 Entering Passive Mode (10,1,1,39,230,116)
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> STOR P17050413383710.jpg
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 150 Connection accepted
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 226 Transfer OK
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> QUIT
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> 221 Goodbye
(000105)4/05/2017 13:38:23 PM - point (10.1.1.20)> disconnected
Is something not setup with the B4J FTPServer?

Tom
 

TomDuncan

Active Member
Licensed User
Here are the log files.
1st one is from Filezilla to prove it works.
Copied a doc file
2nd one is from the ip-camera doing a test.
Sets up a folder (date) then 'images'
..

B4X:
Number of clients: 1
client: AUTH TLS
client: AUTH SSL
client: USER xxx
client: PASS xxx
User logged in: xxx
client: PWD
Number of clients: 2
client: AUTH TLS
client: AUTH SSL
client: USER xxx
client: PASS xxx
User logged in: xxx
client: CWD /
CurrentPath: /
client: PWD
client: TYPE I
client: PASV
client: STOR patient_update.doc
Data connection terminated: /patient_update.doc
client: PASV
client: LIST
Data connection terminated: /
terminated
Number of clients: 1
Number of clients: 2
client: USER xxx
client: PASS xxx
User logged in: xxx
client: TYPE I
client: CWD /20170505/images/
client: QUIT
Number of clients: 1
 

TomDuncan

Active Member
Licensed User
Here is a log from Filezilla Server..

B4X:
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> Connected, sending welcome message...
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> 220-FileZilla Server version 0.9.41 beta
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> 220-written by Tim Kosse (Tim.Kosse@gmx.de)
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> 220 Please visit http://sourceforge.net/projects/filezilla/
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> USER point
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> 331 Password required for point
(003348)5/05/2017 19:35:03 PM - (not logged in) (10.1.1.20)> PASS ********
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 230 Logged on
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> TYPE I
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 200 Type set to I
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> CWD /20170505/images/
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 250 CWD successful. "/20170505/images" is current directory.
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> PASV
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 227 Entering Passive Mode (10,1,1,39,201,255)
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> STOR P17050519352310.jpg
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 150 Connection accepted
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 226 Transfer OK
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> QUIT
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> 221 Goodbye
(003348)5/05/2017 19:35:03 PM - point (10.1.1.20)> disconnected.
and yes the ipcamera does send a PASV command.
 

TomDuncan

Active Member
Licensed User
Put the breakpoint in.
Seems as though the directory on the server is not created.
The FileExists returns false.
 

OliverA

Expert
Licensed User

RichardHirst

Member
Licensed User
Hello Erel, Great work on the Server.

Do you have any way of seeing the Data arrive at the Server End. Is there a "FTP_DownloadProgress" event as in the FTP Client.

Also does the Server support resume..?

Thank You

Richard
 

aidymp

Active Member
Licensed User
Hi,
I use this in a few apps, but now I want to have an option of when the app starts the server is not running, until i turn the feature on, and also would like to be able to turn it off. However It appears that I cannot get it to run out side the starter service? How can I achieve the above?

Thanks

Aidy
 

HAH

Well-Known Member
Licensed User
Is this possible:

B4X:
server.BaseDir = File.DirInternal
 
Status
Not open for further replies.
Top