RCF has built-in support for transferring files. While smaller files can be transferred easily in a single remote call, for example by using a RCF::ByteBuffer
parameter, this technique fails once the size of the file exceeds the maximum message size of the connection.
To reliably transfer a file of arbitrary size, the file needs to be split into chunks and transmitted in separate calls, with the recipient reassembling the chunks to form the destination file. Furthermore, to attain maximum throughput speeds for large transfers, it is also necessary to run network I/O and disk I/O concurrently.
When you use RCF's built in file transfer functionality, these details are taken care of automatically.
File transfers take place on the same connection as any remote calls you make. So if you enable encryption or compression for a RCF client (see Transport Protocols), the settings will apply to any file transfers performed by that RCF client as well.
To use file transfer functionality, you must define RCF_FEATURE_FILETRANSFER=1
in your build (see Building RCF).
To download a file from a RcfServer
, use RCF::ClientStub::downloadFile()
.
The first argument to RCF::ClientStub::downloadFile()
is a download ID, which must be allocated by the RcfServer
. Typically the client will make a remote call to the server, and as part of the response to the remote call, a download ID is allocated by your server-side application code, by calling RCF::RcfSession::configureDownload()
. The download ID is returned to the client.
The client then uses the download ID to actually download the file.
RCF::ClientStub::downloadFile()
also takes a third, optional, argument, of type RCF::FileTransferOptions
. RCF::FileTransferOptions
contains further options for customizing the file transfer, including the ability to download fragments of a file, and assign bandwidth controls to the transfer.
To upload a file to a RcfServer
, use RCF::ClientStub::uploadFile()
.
Uploading files is performed similarly to downloading. The first argument to RCF::ClientStub::uploadFile()
is an upload ID that is assigned by the client, and is used in subsequent remote calls by the client to identify the upload.
Once RCF::ClientStub::uploadFile()
returns, you can pass the upload ID as a parameter in remote calls, and your server-side application code can then retrieve the uploaded file using the upload ID.
Just as for downloads, RCF::ClientStub::uploadFile()
takes a third, optional, argument of type RCF::FileTransferOptions
, with further options for customizing the upload.
Note that on the server-side, RCF::RcfServer::setUploadDirectory()
must be called to specify a location for uploaded files. This property must be set before any uploads can take place.
Once a file has been uploaded to a server, it is the responsibility of your server-side application code to manage its lifetime.
If a network disconnection or other problem occurs during a download, RCF::ClientStub::downloadFile()
will throw an exception. To resume the download, once the connection is re-established, you can call downloadFile()
again, with the same parameters. RCF will resume the download at the point at which it was interrupted.
If a network disconnection or other problem occurs during an upload, RCF::ClientStub::uploadFile()
will throw an exception. To resume the upload, once the connection is re-established, you can call uploadFile()
again, with the same parameters. RCF will resume the upload at the point at which it was interrupted.
On the client-side, to monitor a file transfer, use the RCF::FileTransferOptions
parameter and set RCF::FileTransferOptions::mProgressCallback
to an application-defined callback function. The callback function will be called repeatedly until the file transfer completes.
On the server-side, you can use RCF::RcfServer::setDownloadProgressCallback()
and RCF::RcfServer::setUploadProgressCallback()
, to register a callback which will be called every time a chunk is downloaded or uploaded, for any download or upload on that server.
From the callback you can inspect the associated RCF::RcfSession
, RCF::FileDownloadInfo
and RCF::FileUploadInfo
objects. To cancel a file transfer, throw an exception from the callback.
RCF file transfers will automatically consume as much bandwidth as the network allows. However, in some cases you may want to run file transfers with restricted bandwidth, in order to limit total network bandwidth usage.
You can use RCF::RcfServer::setUploadBandwidthLimit()
and RCF::RcfServer::setDownloadBandwidthLimit()
, to set a maximum total bandwidth to be consumed by all file transfers to and from a RcfServer
.
Here is an example of setting a 1 Mbps upload limit and a 5 Mbps download limit:
If for example three clients connect to this server and begin uploading files, the upload bandwidth consumed by all three clients together, will not be allowed to exceed 1 Mbps.
Similarly, if the three clients are downloading files simultaneously, the total download bandwidth consumed by the clients will not be allowed to exceed 5 Mbps.
RCF also supports setting bandwidth limits on a more granular level, with application-defined subsets of clients sharing a particular bandwidth quota.
For example, on a server connected to multiple networks with varying bandwidth characteristics, you would probably want to limit file transfer bandwidth based on which network the file transfer is taking place on. To do this, use RCF::RcfServer::setUploadBandwidthQuotaCallback()
and RCF::RcfServer::setDownloadBandwidthQuotaCallback()
to configure a callback function for the RcfServer
to call, whenever a file transfer is initiated.
From the callback function you can inspect the RCF::RcfSession
of the connection, and assign a relevant bandwidth quota to the file transfer.
For example, imagine we want to implement the following bandwidth limits:
192.168.*.*
.15.146.*.*
.To implement this, we need three separate RCF::BandwidthQuota
objects, to represent the three bandwidth quotas listed above. Then, we can use RCF::RcfServer::setUploadBandwidthQuotaCallback()
to assign bandwidth quotas based on the IP address of the client:
To assign bandwidth limits from the client-side, use RCF::FileTransferOptions::mBandwidthLimitBps
and RCF::FileTransferOptions::mBandwidthQuotaPtr
.
RCF::FileTransferOptions::mBandwidthLimitBps
allows you to configure a bandwidth limit for a single client connection:
RCF::FileTransferOptions::mBandwidthQuotaPtr
allows you to share a bandwidth quota between multiple client connections. Here is an example of 3 clients uploading files concurrently, with the total bandwidth used by the clients not allowed to exceed 1 Mb/sec: