Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions |

# Network Module

- Introduction
- Working Network Protocol independently with TQUrlOperator and TQNetworkOperation
  - Implementing your own Network Protocol
  - Error Handling

## Introduction

The network module offers classes to make network programming easier and portable. Essentially, there are three sets of classes, first low level classes like TQSocket, TQServerSocket, TQDns, etc. which allow you to work in a portable way with TCP/IP sockets. In addition, there are classes like TQNetworkProtocol, TQNetworkOperation in the TQt base library, which provide an abstract layer for implementing network protocols and TQUrlOperator which operates on such network protocols. Finally the third set of network classes are the passive ones, specifically TQUrl and TQUrlInfo which do URL parsing and similar.

The first set of classes (TQSocket, TQServerSocket, TQDns, TQFtp, etc.) are included in TQt's "network" module.

The TQSocket classes are not directly related to the TQNetwork classes, but TQSocket should and will be used for implementing network protocols, which are directly related to the TQNetwork classes. For example, the TQFtp class (which implements the FTP protocol) uses TQSockets. But TQSockets don't need to be used for protocol implementations, e.g. TQLocalFs (which is an implementation of the local filesystem as network protocol) uses TQDir and doesn't use TQSocket. Using TQNetworkProtocols you can implement everything which fits into a hierarchical structure and can be accessed using URLs. This could be, for example, a protocol which can read pictures from a digital camera using a serial connection.

## Working Network Protocol independently with TQUrlOperator and TQNetworkOperation

It is quite easy to just use existing network protocol implementations and operate on URLs. For example, downloading a file from an FTP server to the local filesystem can be done with following code:

        TQUrlOperator op;
        op.copy( "ftp://ftp.trolltech.com/qt/source/qt-2.1.0.tar.gz", "file:/tmp", false );

And that's all! Of course an implementation of the FTP protocol has to be available and registered for doing that. More information on that later.

You can also do things like creating directories, removing files, renaming, etc. For example, to create a folder on a private FTP account do

        TQUrlOperator op( "ftp://username:password@host.domain.no/home/username" );
        op.mkdir( "New Directory" );

To see all available operations, look at the TQUrlOperator class documentation.

Since networking works asynchronously, the function call for an operation will normally return before the operation has been completed. This means that the function cannot return a value indicating failure or success. Instead, the return value always is a pointer to a TQNetworkOperation, and this object stores all the information about the operation.

For example, TQNetworkOperation has a method which returns the state of this operation. Using this you can find out the state of the operation at any time. The object also makes available the arguments you passed to the TQUrlOperator method, the type of the operation and some more information. For more details see the class documentation of TQNetworkOperation.

The TQUrlOperator emits signals to inform you about the progress of the operations. As you can call many methods which operate on a TQUrlOperator's URL, it queues up all the operations. So you can't know which operation the TQUrlOperator just processed. Clearly you will want to know which operation just took place, so each signal's last argument is a pointer to the TQNetworkOperation object which was just processed and which caused the signal to be emitted.

Some of these operations send a `start()` signal at the beginning (if this makes sense), and some of them send some signals during processing. All operations send a `finished()` signal after they are done. To find that out if an operation finished successfully you can use the TQNetworkOperation pointer you got with the `finished()` signal. If TQNetworkOperation::state() equals TQNetworkProtocol::StDone the operation finished successfully, if it is TQNetworkProtocol::StFailed the operation failed.

Example: A slot which you might connect to the `TQUrlOperator::finished( TQNetworkOperation * )`

    void MyClass::slotOperationFinished( TQNetworkOperation *op )
    {
        switch ( op->operation() ) {
        case TQNetworkProtocol::OpMkDir:
            if ( op->state() == TQNetworkProtocol::StFailed )
                tqDebug( "Couldn't create directory %s", op->arg( 0 ).latin1() );
            else
                tqDebug( "Successfully created directory %s", op->arg( 0 ).latin1() );
            break;
        // ... and so on
        }
    }

As mentioned earlier, some operations send other signals too. Let's take the list children operation as an example (e.g. read a directory on a FTP server):

    TQUrlOperator op;

    MyClass::MyClass() : TQObject(), op( "ftp://ftp.trolltech.com" )
    {
        connect( &op, TQ_SIGNAL( newChildren( const TQValueList<TQUrlInfo> &, TQNetworkOperation * ) ),
                 this, TQ_SLOT( slotInsertEntries( const TQValueList<TQUrlInfo> &, TQNetworkOperation * ) ) );
        connect( &op, TQ_SIGNAL( start( TQNetworkOperation * ) ),
                 this, TQ_SLOT( slotStart( TQNetworkOperation *) ) );
        connect( &op, TQ_SIGNAL( finished( TQNetworkOperation * ) ),
                 this, TQ_SLOT( slotFinished( TQNetworkOperation *) ) );
    }

    void MyClass::slotInsertEntries( const TQValueList<TQUrlInfo> &info, TQNetworkOperation * )
    {
        TQValueList<TQUrlInfo>::ConstIterator it = info.begin();
        for ( ; it != info.end(); ++it ) {
            const TQUrlInfo &inf = *it;
            tqDebug( "Name: %s, Size: %d, Last Modified: %s",
                inf.name().latin1(), inf.size(), inf.lastModified().toString().latin1() );
        }
    }

    void MyClass::slotStart( TQNetworkOperation * )
    {
        tqDebug( "Start reading '%s'", op.toString().latin1() );
    }

    void MyClass::slotFinished( TQNetworkOperation *operation )
    {
        if ( operation->operation() == TQNetworkProtocol::OpListChildren ) {
            if ( operation->state() == TQNetworkProtocol::StFailed )
                tqDebug( "Couldn't read '%s'! Following error occurred: %s",
                    op.toString().latin1(), operation->protocolDetail().latin1() );
            else
                tqDebug( "Finished reading '%s'!", op.toString().latin1() );
        }
    }

These examples demonstrate now how to use the TQUrlOperator and `TQNetworkOperations`. The network extension also contains useful example code.

### Implementing your own Network Protocol

TQNetworkProtocol provides a base class for implementations of network protocols and an architecture for the a dynamic registration and de-registration of network protocols. If you use this architecture you don't need to care about asynchronous programming, as the architecture hides this and does all the work for you.

Note It is difficult to design a base class for network protocols which is useful for all network protocols. The architecture described here is designed to work with all kinds of hierarchical structures, like filesystems. So everything which can be interpreted as hierarchical structure and accessed via URLs, can be implemented as network protocol and easily used in TQt. This is not limited to filesystems only!

To implement a network protocol create a class derived from TQNetworkProtocol.

Other classes will use this network protocol implementation to operate on it. So you should reimplement following protected members

        void TQNetworkProtocol::operationListChildren( TQNetworkOperation *op );
        void TQNetworkProtocol::operationMkDir( TQNetworkOperation *op );
        void TQNetworkProtocol::operationRemove( TQNetworkOperation *op );
        void TQNetworkProtocol::operationRename( TQNetworkOperation *op );
        void TQNetworkProtocol::operationGet( TQNetworkOperation *op );
        void TQNetworkProtocol::operationPut( TQNetworkOperation *op );

Some notes on reimplementing these methods: You always get a pointer to a TQNetworkOperation as argument. This pointer holds all the information about the operation in the current state. If you start processing such an operation, set the state to TQNetworkProtocol::StInProgress. If you finished processing the operation, set the state to TQNetworkProtocol::StDone if it was successful or TQNetworkProtocol::StFailed if an error occurred. If an error occurred you must set an error code (see TQNetworkOperation::setErrorCode()) and if you know some details (e.g. an error message) you can also set this message to the operation pointer (see TQNetworkOperation::setProtocolDetail()). Also you get all the relevant information (type, arguments, etc.) about the operation from the TQNetworkOperation pointer. For details about which arguments you can get and set look at TQNetworkOperation's class documentation.

If you reimplement an operation function, it's very important to emit the correct signals at the correct time: In general always emit `finished()` at the end of an operation (when you either successfully finished processing the operation or an error occurred) with the network operation as argument. The whole network architecture relies on correctly emitted `finished()` signals! Then there are some more specialized signals which are specific to operations:

- Emit in `operationListChildren`:
  - `start()` just before starting to list the children
  - `newChildren()` when new children are read
- Emit in `operationMkDir`:
  - `createdDirectory()` after the directory has been created
  - `newChild()` (or newChildren()) after the directory has been created (since a new directory is a new child)
- Emit in `operationRemove`:
  - `removed()` after a child has been removed
- Emit in `operationRename`:
  - `itemChanged()` after a child has been renamed
- Emit in `operationGet`:
  - `data()` each time new data has been read
  - `dataTransferProgress()` each time new data has been read to indicate how much of the data has been read now.
- Emit in `operationPut`:
  - `dataTransferProgress()` each time data has been written to indicate how much of the data has been written. Although you know the whole data when this operation is called, it's suggested not to write the whole data at once, but to do it step by step to avoid blocking the GUI. Doing things incrementally also means that progress can be made visible to the user.

And remember, always emit the `finished()` signal at the end!

For more details about these signals' arguments look at the TQNetworkProtocol class documentation.

Here is a list of which TQNetworkOperation arguments you can get and which you must set in which function:

(To get the URL on which you should work, use the TQNetworkProtocol::url() method which returns a pointer to the URL operator. Using that you can get the path, host, name filter, etc.)

- In `operationListChildren`:
  - Nothing.
- In `operationMkDir`:
  - `TQNetworkOperation::arg( 0 )` contains the name of the directory which should be created
- In `operationRemove`:
  - `TQNetworkOperation::arg( 0 )` contains the name of the file which should be removed. Normally this is a relative name. But it could be absolute. Use TQUrl( op->arg( 0 ) ).fileName() to get the filename.
- In `operationRename`:
  - `TQNetworkOperation::arg( 0 )` contains the name of the file which should be renamed
  - `TQNetworkOperation::arg( 1 )` contains the name to which it should be renamed.
- In `operationGet`:
  - `TQNetworkOperation::arg( 0 )` contains the full URL of the file which should be retrieved.
- In `operationPut`:
  - `TQNetworkOperation::arg( 0 )` contains the full URL of the file in which the data should be stored.
  - `TQNetworkOperation::rawArg( 1 )` contains the data which should be stored in `TQNetworkOperation::arg( 0 )`

In summary: If you reimplement an operation function, you must emit some special signals and at the end you must always emit a `finished()` signal, regardless of success or failure. Also you must change the state of the TQNetworkOperation during processing. You can also get and set TQNetworkOperation arguments as the operation progresses.

It may occur that the network protocol you implement only requires a subset of these operations. In such cases, simply reimplement the operations which are supported by the protocol. Additionally you must specify which operations you support. This is achieved by reimplementing

        int TQNetworkProtocol::supportedOperations() const;

In your implementation of this method return an `int` value which is constructed by OR-ing together the correct values (supported operations) of the following enum (of TQNetworkProtocol):

- `OpListChildren`
- `OpMkDir`
- `OpRemove`
- `OpRename`
- `OpGet`
- `OpPut`

For example, if your protocol supports listing children and renaming them, your implementation of `supportedOperations()` should do this:

        return OpListChildren | OpRename;

The last method you must reimplement is

        bool TQNetworkProtocol::checkConnection( TQNetworkOperation *op );

Here you must return true, if the connection is up and okay (this means operations on the protocol can be done). If the connection is not okay, return false and start to try opening it. If you cannot open the connection at all (e.g. because the host is not found), emit a `finished()` signal and set an error code and the TQNetworkProtocol::StFailed state to the TQNetworkOperation pointer you get here.

Now, you never need to check before doing an operation yourself, if the connection is okay. The network architecture does this, which means it uses `checkConnection()` to see if an operation can be done and if not, it tries it again and again for some time, only calling an operation function if the connection is okay.

To be able to use a network protocol with a TQUrlOperator (and so, for example, in the TQFileDialog), you must register the network protocol implementation. This can be done like this:

        TQNetworkProtocol::registerNetworkProtocol( "myprot", new TQNetworkProtocolFactory<MyProtocol> );

In this case `MyProtocol` would be a class you implemented as described here (derived from TQNetworkProtocol) and the name of the protocol would be "myprot". So to use it, you would do something like

        TQUrlOperator op( "myprot://host/path" );
        op.listChildren();

Finally, as example of a network protocol implementation you could look at the implementation of TQLocalFs. The network extension also contains an example implementation of a network protocol.

### Error Handling

Error handling is important for both implementing new network protocols for and using them (through TQUrlOperator).

After processing an operation has been finished the network operation the TQUrlOperator emits the `finished()` signal. This has as argument a pointer to the processed TQNetworkOperation. If the state of this operation is TQNetworkProtocol::StFailed, the operation contains some more information about this error. The following error codes are defined in TQNetworkProtocol:

Error | Meaning
--- | ---
TQNetworkProtocol::NoError | No error occurred
TQNetworkProtocol::ErrValid | The URL you are operating on is not valid
TQNetworkProtocol::ErrUnknownProtocol | There is no protocol implementation available for the protocol of the URL you are operating on (e.g. if the protocol is http and no http implementation has been registered)
TQNetworkProtocol::ErrUnsupported | The operation is not supported by the protocol
TQNetworkProtocol::ErrParse | Parse error of the URL
TQNetworkProtocol::ErrLoginIncorrect | You needed to login but the username or password are wrong
TQNetworkProtocol::ErrHostNotFound | The specified host (in the URL) couldn't be found
TQNetworkProtocol::ErrListChildren | An error occurred while listing the children
TQNetworkProtocol::ErrMkDir | An error occurred when creating a directory
TQNetworkProtocol::ErrRemove | An error occurred while removing a child
TQNetworkProtocol::ErrRename | An error occurred while renaming a child
TQNetworkProtocol::ErrGet | An error occurred while getting (retrieving) data
TQNetworkProtocol::ErrPut | An error occurred while putting (uploading) data
TQNetworkProtocol::ErrFileNotExisting | A file which is needed by the operation doesn't exist
TQNetworkProtocol::ErrPermissionDenied | The permission for doing the operation has been denied

TQNetworkOperation::errorCode() returns one of these codes or perhaps a different one if you use your an own network protocol implementation which defines additional error codes.

`TQNetworkOperation::protocolDetails()` may also return a string which contains an error message then which might be suitable for display to the user.

If you implement your own network protocol, you must report any errors which occurred. First you always need to be able to access the TQNetworkOperation which is being processed at the moment. This is done using `TQNetworkOperation::operationInProgress()`, which returns a pointer to the current network operation or 0 if no operation is processed at the moment.

Now if an error occurred and you need to handle it, do this:

        if ( operationInProgress() ) {
            operationInProgress()->setErrorCode( error_code_of_your_error );
            operationInProgress()->setProtocolDetails( detail ); // optional
            emit finished( operationInProgress() );
            return;
        }

That's all. The connection to the TQUrlOperator and so on is done automatically. Additionally, if the error was really bad so that no more operations can be done in the current state (e.g. if the host couldn't be found), call `TQNetworkProtocol::clearOperationStack()` before emitting `finished()`.

Ideally you should use one of the predefined error codes of TQNetworkProtocol. If this is not possible, you can add own error codes - they are just normal `int`s. Just be careful that the value of the error code doesn't conflict with an existing one.

An example to look at is in qt/examples/network/ftpclient. This is the implementation of a fairly complete FTP client, which supports uploading and downloading files, making directories, etc., all done using `TQUrlOperators`.

You might also like to look at TQFtp (in qt/src/network/qftp.cpp) or at the example in qt/examples/network/networkprotocol/nntp.cpp.