PrevNextUpHome BREW C++ Class Library & GUI Framework & XML Middleware : SophiaFramework 4.1

16.3. Socket Communication

There are three types of classes for socket communication.

Table 16.2. Socket communication classes

Class Name Description
SFXTCPSocket Class for the TCP socket communication.
SFXSSLSocket Class for the SSL socket communication.
SFXUDPSocket Class for the UDP socket communication.
[Caution] About MIF File Setting

Never forget to turn on the Network option in the MIF file setting of privilege level.

16.3.1. TCP Socket Communication

SFXTCPSocket is the class that performs the TCP Socket communication as described in the following procedure.

  1. Create the SFXTCPSocket instance.
  2. Open the TCP Socket using the SFXTCPSocket::Open funtion.
  3. Connect to the server using the SFXTCPSocket::Connect function, and also register the callback function.
  4. The registered callback function will be called after the connection is established.
  5. To receive data, use the input stream.
  6. To send data, use the output stream.
  7. Step 5. and 6. are repeated until no other data needs to be sent or received.
  8. Finally, close the TCP Socket using the SFXTCPSocket::Close function.

Example 16.10. Get the time from NTP server

// SFXTCPSocket instance is defined as class member variable for the callback function
class NetworkTime {
private:
    SFXTCPSocket _tcp;
    SFXBinaryStreamReader _reader;

public:
    Void Start(Void); // start to connect NTP server
    Void Stop(Void);  // stop connecting to NTP server
    
    // declare callback function
    CALLBACK_DECLARE_SFXTCPSOCKET(OnConnect)
    CALLBACK_DECLARE_SFXBINARYSTREAMREADER(OnFetch)
};

// start to connect NTP server
Void NetworkTime::Start(Void)
{
    SFCError error(SFERR_NO_ERROR);
    // NTP server address
    SFXSocketAddress address("www.example.com:37");

    // initial processing
    if ((error = _tcp.Open()) == SFERR_NO_ERROR) {

        // start to connect (connection establishment will be notified to OnConnect function)
        if ((error = _tcp.Connect(address,
                CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
            
            TRACE("connecting...");

        }
        else {
            // if error occurs, close connection
            _tcp.Close();
        }
    }
	
    if (error != SFERR_NO_ERROR) { 
        // if error occurs
        // error handling
        ...
    }
    return;
}

// stop connecting to NTP server
Void NetworkTime::Stop(Void)
{
    // termination processing
    _reader.Release();
    _tcp.Close();
    return;
}

// callback function notified of connection establishment
CALLBACK_IMPLEMENT_SFXTCPSOCKET(NetworkTime, OnConnect, error)
{
    if (error == SFERR_NO_ERROR) {

        // get input stream
        if ((error = _tcp.GetStreamReader(64, &_reader)) == SFERR_NO_ERROR) {

            // receive data (completion of receiving 4 bytes of data will be notified to OnFetch function )
            if ((error = _reader.Fetch(4, CALLBACK_FUNCTION(OnFetch)))
                == SFERR_NO_ERROR) {
                TRACE("fetching...");
            }
            if (error != SFERR_NO_ERROR) { 
                // if error occurs
                // release resource
                _reader.Release();
            }
        }
    }
	
    if (error != SFERR_NO_ERROR) {  
        // if error occurs
        _tcp.Close();
    }
    return;
}

// callback function notified of completion of receiving 4 bytes of data
CALLBACK_IMPLEMENT_SFXBINARYSTREAMREADER(NetworkTime, OnFetch, error)
{
    SFXDate date; // date class
    UInt32 time;

    if (error == SFERR_NO_ERROR) {

        // read data as big endian
        _reader.SetEndian(SFXBinaryStreamReader::ENDIAN_BIG);
        
        // read data as UInt32 type, then store to time
        if ((error = _reader.ReadUInt32(&time)) == SFERR_NO_ERROR) {
            
            // set value of time to SFXDate instance
            date.Set(time);
            
            // adjust time from January 1, 1900
            date -= SFXDateDuration::Offset19000101();
            
            // convert time into local time
            date += SFXDateDuration::LocalTimeOffset();

            // output time in specified format
            TRACE("%s", date.Format("YYYY/MM/DD hh:mm:ss").GetCString());
        }
    }
	
    if (error != SFERR_NO_ERROR) {
        // if error occurs
        // error handling
        ...
    }

    // termination processing
    _reader.Release();
    _tcp.Close();
    return;
}

16.3.2. SSL Socket Communication

SFXSSLSocket is the class that performs the SSL Socket communication as described in the following procedure.

  1. Create the SFXSSLSocket instance.
  2. Open the SSL Socket using the SFXSSLSocket::Open function.
  3. Set the trust mode(default: SSL_TRUST_MODE_FAIL) using the SFXSSLSocket::SetTrustMode function.
  4. Connect to the server using the SFXSSLSocket::Connect funtion, and also regiter the callback function.
  5. The registered callback function will be called after the connection is established.
  6. Negotiate with the server using the SFXSSLSocket::Negotiate function, and also regiter the callback function.
  7. The registered callback function will be called after negotiation is completed.
  8. To receive data, use the input stream.
  9. To send data, use the output stream.
  10. Step 8. and 9. are repeated until no other data needs to be sent or received.
  11. Finally, close the SSL Socket using the SFXSSLSocket::Close function.

Example 16.11. SSL Socket Communication

// bold lines are places different from TCP
// SFXSSLSocket instance is usually defined as class member variable for the callback function
class MyClass {
private:
    SFXSSLSocket _socket;
    SFXAnsiStringStreamWriter _writer; // output stream
    SFXAnsiStringStreamReader _reader; // input stream

public:
    Void Start(Void);

    // callback functions
    CALLBACK_DECLARE_SFXSSLSOCKET(OnConnect)
    CALLBACK_DECLARE_SFXSSLSOCKET(OnNegotiate)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMWRITER(OnFlush)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch)
};

Void MyClass::Start(Void)
{
    SFCError error;
    SFXSocketAddress host("www.example.com:995");

    // open socket
    if ((error = _socket.Open()) == SFERR_NO_ERROR) {
 
        // connect to www.example.com:443
        // host name is automatically resolved ( connection establishment will be notified to OnConnect function )
        error = _socket.Connect(host, CALLBACK_FUNCTION(OnConnect));
    }
    if (error != SFERR_NO_ERROR) { 
        // if error occurs
        _socket.Close();
    }
    return;
}

// callback function notified of connection establishment
CALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnConnect, error)
{
    if (error == SFERR_NO_ERROR) { 
        // if error occurs
        // negotiate( negotiation completion will be notified to OnNegotiate function )
        error = _socket.Negotiate(CALLBACK_FUNCTION(OnNegotiate));
    }
    if (error != SFERR_NO_ERROR) { 
        // if error occurs
        _socket.Close();
    }
    return;
}

// callback function notified of negotiation completion
CALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnNegotiate, error)
{
    static AChar sendingMessage[] = "GET / HTTP/1.0\r\n\r\n";

    if (error == SFERR_NO_ERROR) {

        // get output stream (buffer size: 1024 )
        if ((error = _socket.GetStreamWriter(1024, &_writer))
            == SFERR_NO_ERROR) {

            // write data into output stream
            if ((error = _writer.Write(sendingMessage,
                   lengthof(sendingMessage))) == SFERR_NO_ERROR) {

                // send data written in output stream actually (completion of sending data actually will be notified to OnFlush function)
                error = _writer.Flush(CALLBACK_FUNCTION(OnFlush));
            }
            if (error != SFERR_NO_ERROR) { 
                // if error occurs
                 _writer.Release();
            }
        }
    }
    if (error != SFERR_NO_ERROR) { 
       // if error occurs
       _socket.Close();
    }
    return;
}

// callback function notified of completion of sending data
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMWRITER(MyClass, OnFlush, error)
{
    // release output stream after sending data
    _writer.Release();

    if (error == SFERR_NO_ERROR) {

        // get input stream (buffer size: 1024)
        if ((error = _socket.GetStreamReader(1024, &_reader))
            == SFERR_NO_ERROR) {

            // receive data ( completion of receiving data will be notified to OnFetch function )
            if ((error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch)))
                != SFERR_NO_ERROR) {
                // if error occurs
               _reader.Release(); 
            }
        }
    }
    if (error != SFERR_NO_ERROR) { 
        // if error occurs
        _socket.Close();
    }
    return;
}

// callback function notified of completion of receiving data
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error)
{
    SFXAnsiString receivedString;

    if (error == SFERR_NO_ERROR) {

        // receive data from input stream
        _reader >> receivedString;

        // display data received
        TRACE("%s", receivedString.GetCString());
    }
    // release input stream after receiving data
    _reader.Release();

    // close socket
    _socket.Close();
    return;
}

16.3.3. UDP Socket Communication

SFXUDPSocket is the class that performs the UDP Socket communication as described in the following procedure.

  1. Create the SFXUDPSocket instance.
  2. Open the UDP Socket using the SFXUDPSocket::Open function.
  3. Bind local IP address and port number with the UDP Socket using the SFXUDPSocket::Bind function. If the return value of SFXUDPSocket::Bind function is AEE_NET_WOULDBLOCK(this means that the bind request is blocked), register the callback function in which the SFXUDPSocket::Bind function will be called for binding again.
  4. Send data asynchronously using the SFXUDPSocket::Send function. And set the IP address and port number of receiver using the SFXUDPSocket::Send function.
  5. Receive data asynchronously using the SFXUDPSocket::Receive function. And the IP address and port number of sender can be received using the SFXUDPSocket::Receive function.
  6. Step 4. and 5. are repeated until all data is sent or received.
  7. Finally, close the UDP Socket using the SFXUDPSocket::Close function.

Example 16.12. UDP Socket Communication

// SFXUDPSocket instance is usually defined as class member variable for the callback function
class MyClass {
private:
    SFXUDPSocket _socket;

public:
    Void Start(Void);

    // callback functions
    CALLBACK_DECLARE_SFXUDPSOCKET(OnBind)
    CALLBACK_DECLARE_SFXUDPSOCKET(OnSend)
    CALLBACK_DECLARE_SFXUDPSOCKET(OnReceive)
};

Void MyClass::Start(Void)
{
    SFCError error;

    // open UDP socket
    if ((error = _socket.Open()) == SFERR_NO_ERROR) {

        // bind local IP address and port number to UDP socket
        OnBind(SFERR_NO_ERROR);
    
    }
    return;
}

// callback function notified of completion of binding
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnBind, error)
{
    SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024);

    // check whether or not error occurs
    if (error == SFERR_NO_ERROR) {

        error = _socket.Bind(address);

        switch (error) {
            case SFERR_NO_ERROR:

                // send data asynchronously
                OnSend(SFERR_NO_ERROR);
                break;
            case AEE_NET_WOULDBLOCK:

                // register callback function notified of completion of binding
                _socket.ScheduleBind(CALLBACK_FUNCTION(OnBind));
                break;
        }
    }
    return;
}

// callback function notified of completion of sending data
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnSend, error)
{
    static ACharConst data[] = "udp!";
    SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024);
    UInt32 size;

    // check error
    if (error == SFERR_NO_ERROR) {
        size = sizeof(data) - 1;

        // send data asynchronously
        error = _socket.Send(address, data, &size);

        switch (error) {
            case SFERR_NO_ERROR:

                // check whether data of specified size is written or not
                // SFXUDPSocket::Send function may not send data of specified size at a time
                // here for simple explanation, display error message

                if (size == sizeof(data) - 1) {

                    // receive data asynchronously
                    OnReceive(SFERR_NO_ERROR);
                }
                else {
                    TRACE("...failed to send ...");
                }
                break;
            case AEE_NET_WOULDBLOCK:

                // register callback function notified of completion of sending data
                _socket.ScheduleSend(CALLBACK_FUNCTION(OnSend));
                break;
        }
    }
    return;
}

// callback function notified of completion of receiving data
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnReceive, error)
{
    SFXSocketAddress socket;
    SFXBuffer buffer;
    UInt32 size;

    // check error
    if (error == SFERR_NO_ERROR) {
        buffer.SetSize(4);

        size = static_cast<UInt16>(buffer.GetSize());

        // receive data asynchronously
        switch (_socket.Receive(&socket, buffer.GetBuffer(), &size)) {
            case SFERR_NO_ERROR:

                // check whether data of specified size is read or not
                // SFXUDPSocket::Receive function may not receive data of specified size at a time
                // here for simple explanation, display error message

                if (size == buffer.GetSize()) {

                    // display received data
                    buffer.SetSize(buffer.GetSize() + 1);
                    buffer[buffer.GetSize() - 1] = '\0';
                    TRACE(":%s", SFXAnsiString(buffer).GetCString());

                    // close socket
                    _socket.Close();
                }
                else {
                    TRACE("...failed to receive...");
                }
                break;
            case AEE_NET_WOULDBLOCK:

                // register callback function notified of completion of receiving data
                _socket.ScheduleReceive(CALLBACK_FUNCTION(OnReceive));
                break;
        }
    }
    return;
}