SophiaFramework UNIVERSE 5.3 |
ソケット通信を行うためのクラスとして、以下の 3 種類のクラスがあります。
表 16.2. ソケット通信クラス
クラス名 | 解説 |
---|---|
SFXTCPSocket | TCP ソケット通信のためのクラスです。 TCP クライアント、またはTCP サーバーを実装するための機能を提供します。 |
SFXSSLSocket | SSL ソケット通信のためのクラスです。 SSL クライアントを実装するための機能を提供します。 |
SFXUDPSocket | UDP ソケット通信のためのクラスです。 UDP クライアント、またはUDP サーバーを実装するための機能を提供します。 |
ストリームを利用したデータ送受信 | |
---|---|
SFXTCPSocket / SFXSSLSocket クラスでは、 ストリームを利用したデータ送受信が可能です。 また、ストリームを利用せずに Write / Read 関数を使用してデータを送受信することも可能です。 SFXUDPSocket クラスでは、ストリームを利用してデータを送受信することができません。 SFXUDPSocket::Send / SFXUDPSocket::Receive 関数を使用してデータを送受信します。 |
mif ファイルの設定 | |
---|---|
ソケット通信を行うには、 mif ファイルの特権レベル設定で「ネットワーク」の項目をオンにする必要があります。 |
SFXTCPSocket クラスは、 TCP クライアントと TCP サーバーを実装する機能を提供します。
このクラスでは、ストリームを利用したデータ送受信が可能です。
ストリームを利用しない場合は SFXTCPSocket::Write / SFXTCPSocket::Read 関数を使用してデータを送受信します。
TCP クライアントは、 SFXTCPSocket クラスを使用して以下の手順で実装します。
例 16.12. NTP サーバーからの時刻取得
// コールバック関数で使用するので、_socket はクラスのメンバ変数として定義する class NetworkTime { private: SFXTCPSocket _socket; SFXBinaryStreamReader _reader; SFXTimer _timer; public: Void Start(Void); // NTP サーバーとの接続を開始する Void Stop(Void); // NTP サーバーとの接続を終了する // コールバック関数の宣言 XALLBACK_DECLARE_SFXTCPSOCKET(OnConnect) XALLBACK_DECLARE_SFXBINARYSTREAMREADER(OnFetch) XALLBACK_DECLARE_SFXTIMER(OnTimer) }; #define NTP_SERVER ("www.example.com:37") #define TIMER_INTERVAL (5000) // NTP サーバーへの接続を開始する(アプリ開始時またはレジューム時に呼び出す) Void NetworkTime::Start(Void) { SFCError error(SFERR_NO_ERROR); // NTP サーバーのドメイン名とポート番号を設定する SFXSocketAddress address(NTP_SERVER); // タイマーコールバック関数を設定する _timer.Set(XALLBACK_INTERNAL(OnTimer)); // ソケットを初期化する if ((error = _socket.Open()) == SFERR_NO_ERROR) { // NTP サーバーに接続する // ※1. 接続要求の結果は、OnConnect 関数に通知される // ※2. ドメイン名の解決は自動的に行われる if ((error = _socket.Connect(address, XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { TRACE("> connecting..."); } else { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... // タイマーをセットする。TIMER_INTERVAL ミリ秒後に OnTimer 関数が呼び出される _timer.Schedule(TIMER_INTERVAL); } return; } // NTP サーバーへの接続を終了する(アプリ終了時またはサスペンド時に呼び出す) Void NetworkTime::Stop(Void) { // 終了処理 // ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(NetworkTime, OnConnect, error) { if (error == SFERR_NO_ERROR) { // データ受信用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(バッファサイズ: 64 バイト) if ((error = _socket.GetStreamReader(64, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: 実際にソケットからストリームバッファに 4 バイトのデータを受信する // ※ データ受信(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(4, XALLBACK_INTERNAL(OnFetch))) == SFERR_NO_ERROR) { TRACE("> fetching..."); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ストリームを解放する _reader.Release(); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // データ受信(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXBINARYSTREAMREADER(NetworkTime, OnFetch, error) { SFXDate date; // 日付クラス UInt32 time; if (error == SFERR_NO_ERROR) { // ビッグエンディアンとしてデータを読み込む _reader.SetEndian(SFXBinaryStreamReader::ENDIAN_BIG); // ストリームバッファから time 変数に UInt32 型データを読み込む if ((error = _reader.ReadUInt32(&time)) == SFERR_NO_ERROR) { // time 変数の値を SFXDate インスタンスに設定する date.Set(time); // 受信したデータは 1900 年 1 月 1 日 からの時刻なので調整する date -= SFXDateDuration::Offset19000101(); // 時刻をローカル時刻に変換する date += SFXDateDuration::LocalTimeOffset(); // 時刻を書式に合わせて出力する TRACE("%s", date.Format("YYYY/MM/DD hh:mm:ss").GetCString()); } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... } // 終了処理 // ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); return; } // タイマーコールバック関数 XALLBACK_IMPLEMENT_SFXTIMER(NetworkTime, OnTimer) { Start(); return; }
注意 | |
---|---|
サスペンドとレジュームに対応した networktime アプリのサンプルコードが、 SophiaFramework UNIVERSE パッケージの Example/networktime フォルダにあります。 |
TCP サーバーは、 SFXTCPSocket クラスを使用して以下の手順で実装します。
以下は、ループバックで TCP クライアントと TCP サーバーが通信するコードです。
例 16.13. TCP サーバーの実装
// コールバック関数で使用するので、_socket* はクラスのメンバ変数として定義する SFMTYPEDEFCLASS(MyClass) class MyClass { SFMSEALCOPY(MyClass) public: static SFCInvokerPtr Factory(Void); private: SFXTCPSocket _socket1; // TCP サーバー接続リクエスト受付ソケット SFXTCPSocket _socket2; // TCP サーバー通信用ソケット SFXTCPSocket _socket3; // TCP クライアント通信用ソケット Void ServerStart(Void); // TCP サーバーの開始 Void ClientStart(Void); // TCP クライアントの開始 Void Stop(Void); // TCP サーバー/クライアントの終了 // コールバック関数 XALLBACK_DECLARE_SFXTCPSOCKET(/OnBind) XALLBACK_DECLARE_SFXTCPSOCKET(OnListen) XALLBACK_DECLARE_SFXTCPSOCKET(OnAccept) XALLBACK_DECLARE_SFXTCPSOCKET(OnConnect) XALLBACK_DECLARE_SFXTCPSOCKET(OnWrite) XALLBACK_DECLARE_SFXTCPSOCKET(OnRead) }; // TCP サーバーを開始する Void MyClass::ServerStart(Void) { SFCError error(SFERR_NO_ERROR); TRACE("Start!"); // TCP サーバー接続リクエスト受付ソケットを開く if ((error = _socket1.Open()) == SFERR_NO_ERROR) { TRACE("Server Socket for Accepting the Client Requests Is Opened!"); // Bind する OnBind(error); } else { // エラーが発生したとき Stop(); TRACE("Fatal Open Error of the Server Socket for Accepting the Client Requests = %d", error); } } // TCP クライアントを開始する Void chelloworld::ClientStart(Void) { SFCError error(SFERR_NO_ERROR); SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024); // TCP サーバーのアドレス // ※外部のサーバーへ接続する場合は、実際の IP アドレスまたはドメイン名を指定する TRACE("Now, TCP Client Has Started."); if ((error=_socket3.Open())== SFERR_NO_ERROR) { TRACE("Client Socket for Communicating with the Sever Has Opened!"); // サーバーへ接続する if ((error = _socket3.Connect(address, XALLBACK_INTERNAL(OnConnect))) == SFERR_NO_ERROR) { TRACE("connecting..."); } else { // エラーが発生したとき TRACE("Fatal Connect Error = %d", error); Stop(); } } else { // エラーが発生したとき Stop(); TRACE("Fatal Client Socket Open Error = %d", error); } return; } // TCP サーバー/クライアントの終了 Void MyClass::Stop(Void) { _socket1.Close(); _socket2.Close(); _socket3.Close(); return; } // Bind 可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnBind, error) { TRACE("Error at the Start of OnBind() = %d", error); SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024); // TCP サーバーのアドレス // ※外部のクライアントと接続する場合は、SFXInetAddress::AnyInetAddress() を指定する if (error == SFERR_NO_ERROR) { switch (error = _socket1.Bind(address)) { case SFERR_NO_ERROR: // Listen する OnListen(error); break; case AEE_NET_WOULDBLOCK: // Bind がブロックされたとき // Bind をスケジュールする: OnBind コールバック関数を登録する // ※ OnBind コールバック関数は Bind が可能になれば BREW AEE により呼び出される TRACE("Schedule Bind."); _socket1.ScheduleBind(XALLBACK_INTERNAL(OnBind)); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnBind Error = %d", error); break; } } else { // エラーが発生したとき Stop(); TRACE("Fatal OnBind Error = %d", error); } return; } // Listen 可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnListen, error) { TRACE("Error at the Start of OnListen() = %d", error); SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024); // TCP サーバーのアドレス if (error == SFERR_NO_ERROR) { // Listen する switch (error = _socket1.Listen()) { case SFERR_NO_ERROR: // TCP クライアントを開始する StartClient(); // Accept する OnAccept(error); break; case AEE_NET_WOULDBLOCK: // Listen がブロックされたとき // Listen をスケジュールする: OnListen コールバック関数を登録する // ※ OnListen コールバック関数は Listen が可能になれば BREW AEE により呼び出される TRACE("Schedule Listen."); _socket1.ScheduleListen(XALLBACK_INTERNAL(OnListen)); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnListen Error = %d", error); break; } } else { // エラーが発生したとき Stop(); TRACE("Fatal OnListen Error = %d", error); } return; } // Accept 可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnAccept, error) { TRACE("Error at the Start of OnAccept() = %d", error); if (error == SFERR_NO_ERROR) { switch (error = _socket1.Accept(&_socket2)) { case SFERR_NO_ERROR: // クライアントからのデータを受信する OnRead(error); break; case AEE_NET_WOULDBLOCK: // Accept がブロックされたとき // Accept をスケジュールする: OnAccept コールバック関数を登録する // ※ OnAccept コールバック関数は Accept が可能になれば BREW AEE により呼び出される TRACE("Schedule Accept."); _socket1.ScheduleAccept(XALLBACK_INTERNAL(OnAccept)); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnAccept Error = %d", error); break; } } else { // エラーが発生したとき Stop(); TRACE("Fatal OnAccept Error = %d", error); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnConnect, error) { TRACE("Error at the Start of OnConnect() = %d", error); switch (error) { case SFERR_NO_ERROR: // サーバー接続に成功した! TRACE("Connected!"); // データを送信する OnWrite(error); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnConnect Error = %d", error); break; } return; } // Write(データ送信)可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnWrite, error) { TRACE("Error at the Start of OnWrite() = %d", error); static ACharConst data[] = "hello world!"; UInt32 size = sizeof(data) - 1; if (error == SFERR_NO_ERROR) { // サーバーへデータを送信する switch (error = _socket3.Write(data, &size)) { case SFERR_NO_ERROR: // データ送信に成功した! TRACE("Data has been sent!"); break; case AEE_NET_WOULDBLOCK: // データ送信がブロックされたとき // Write をスケジュールする: OnWrite コールバック関数を登録する // ※ OnWrite コールバック関数は Write 可能になれば BREW AEE により呼び出される TRACE("Schedule Write."); _socket3.ScheduleWrite(XALLBACK_INTERNAL(OnWrite)); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnWrite Error = %d", error); break; } } return; } // Read(データ受信)可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnRead, error) { TRACE("Error at the Start of OnRead() = %d", error); SFXBuffer buffer; UInt32 size(1024); buffer.SetSize(size); if (error == SFERR_NO_ERROR) { // クライアントからデータを受信する switch (error = _socket2.Read(buffer.GetBuffer(), &size)) { case SFERR_NO_ERROR: // データ受信に成功した! TRACE("Data has been reveived!"); // 受信したデータを表示する buffer.SetSize(size + 1); buffer[buffer.GetSize() - 1] = '\0'; TRACE("Received Data: %s", SFXAnsiString(buffer).GetCString()); Stop(); break; case AEE_NET_WOULDBLOCK: // データ受信がブロックされたとき // Read をスケジュールする: OnRead コールバック関数を登録する // ※ OnRead コールバック関数は Read 可能になれば BREW AEE により呼び出される TRACE("Schedule Read."); _socket2.ScheduleRead(XALLBACK_INTERNAL(OnRead)); break; default: // エラーが発生したとき Stop(); TRACE("Fatal OnRead Error = %d", error); break; } } return; }
クライアントとサーバーが異なる端末のとき | |
---|---|
クライアントとサーバーが異なる端末のときは、 下記の変更により TCP サーバーと TCP クライアントを実装します。
|
SFXSSLSocket クラスは、 SSL クライアントを実装する機能だけを提供します。 SSL サーバーを実装する機能は提供しません。
このクラスでは、ストリームを利用したデータ送受信が可能です。
ストリームを利用しない場合は SFXSSLSocket::Write / SFXSSLSocket::Read 関数を使用してデータを送受信します。
SSL クライアントは、 SFXSSLSocket クラスを使用して以下の手順で実装します。
例 16.14. SSL クライアントの実装
// コールバック関数で使用するので、_socket はクラスのメンバ変数として定義する class MyClass { private: SFXSSLSocket_socket; // SSL ソケット SFXAnsiStringStreamWriter _writer; // データ送信用ストリーム SFXAnsiStringStreamReader _reader; // データ受信用ストリーム public: Void Start(Void); // コールバック関数 XALLBACK_DECLARE_SFXSSLSOCKET(OnConnect) XALLBACK_DECLARE_SFXSSLSOCKET(OnNegotiate) XALLBACK_DECLARE_SFXANSISTRINGSTREAMWRITER(OnFlush) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) }; Void MyClass::Start(Void) { SFCError error; SFXSocketAddress host("www.example.com:995"); // ソケットを開く if ((error = _socket.Open()) == SFERR_NO_ERROR) { // サーバーに接続する // ※1. 接続要求の結果は、OnConnect 関数に通知される // ※2. ホスト名(host)は自動的に解決される error = _socket.Connect(host, XALLBACK_INTERNAL(OnConnect)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnConnect, error) { if (error == SFERR_NO_ERROR) { // エラーが発生していないとき // サーバーとの SSL ネゴシエーションを行う // ※ SSL ネゴシエーションの結果は OnNegotiate 関数に通知される error = _socket.Negotiate(XALLBACK_INTERNAL(OnNegotiate)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // SSL ネゴシエーションの結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnNegotiate, error) { // 送信する文字列 static AChar message[] = "GET / HTTP/1.0\r\n\r\n"; if (error == SFERR_NO_ERROR) { // データ送信用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(バッファサイズ: 1024 バイト) if ((error = _socket.GetStreamWriter(1024, &_writer)) == SFERR_NO_ERROR) { // message 変数からストリームバッファにデータを書き込む if ((error = _writer.Write(message, lengthof(message))) == SFERR_NO_ERROR) { // フラッシュを行う: 実際にストリームバッファからソケットにデータを送信する // ※ データ送信(フラッシュ)の結果は、OnFlush 関数に通知される error = _writer.Flush(XALLBACK_INTERNAL(OnFlush)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ送信用ストリームを解放する _writer.Release(); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // データ送信(フラッシュ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMWRITER(MyClass, OnFlush, error) { // 送信が終わったのでデータ送信用ストリームを解放する _writer.Release(); if (error == SFERR_NO_ERROR) { // データ受信用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(バッファサイズ: 1024 バイト) if ((error = _socket.GetStreamReader(1024, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: 実際にソケットからストリームバッファにデータを受信する // ※ データ受信(フェッチ)の結果は、OnFetch 関数に通知される if ((error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch))) != SFERR_NO_ERROR) { // エラーが発生したとき // データ受信用ストリームを解放する _reader.Release(); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // データ受信(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む _reader > string; // string 変数の内容をデバッグウィンドウに表示する TRACE("%s", string.GetCString()); } // 受信が終わったのでデータ受信用ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); return; }
SFXUDPSocket クラスは、 UDP クライアント、またはUDP サーバーを実装するための機能を提供します。
このクラスでは、ストリームを利用してデータ送受信することはできません。 SFXUDPSocket::Send / SFXUDPSocket::Receive 関数を呼び出してデータを送受信します。
UDP クライアントは、 SFXUDPSocket クラスを使用して以下の手順で実装します。
注意 | |
---|---|
UDP ソケットからデータを受信するには、 ローカル の IP アドレスとポート番号を UDP ソケットにバインドして UDP サーバーを実装する必要があります。 |
UDP サーバーは、 SFXUDPSocket クラスを使用して以下の手順で実装します。
注意 | |
---|---|
UDP サーバーは、 UDP クライアントとして別の UDP サーバーにデータを送信することも可能です。 |
例 16.15. UDP クライアント兼サーバーの実装
// コールバック関数で使用するので、_socket はクラスのメンバ変数として定義する class MyClass { private: SFXUDPSocket _socket; // UDP ソケット public: Void Start(Void); // コールバック関数 XALLBACK_DECLARE_SFXUDPSOCKET(OnBind) XALLBACK_DECLARE_SFXUDPSOCKET(OnSend) XALLBACK_DECLARE_SFXUDPSOCKET(OnReceive) }; Void MyClass::Start(Void) { SFCError error; // ソケットを開く if ((error = _socket.Open()) == SFERR_NO_ERROR) { // ソケットをローカル の IP アドレスとポート番号にバインドする OnBind(SFERR_NO_ERROR); } return; } // Bind 可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnBind, error) { SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024); // エラーが発生したかどうかチェックする if (error == SFERR_NO_ERROR) { error = _socket.Bind(address); switch (error) { case SFERR_NO_ERROR: // データを送信する OnSend(SFERR_NO_ERROR); break; case AEE_NET_WOULDBLOCK: // バインドがブロックされたとき // Bind をスケジュールする: OnBind コールバック関数を登録する // ※ OnBind コールバック関数は Bind 可能になれば BREW AEE により呼び出される _socket.ScheduleBind(XALLBACK_INTERNAL(OnBind)); break; } } return; } // Send(データ送信)可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnSend, error) { static ACharConst data[] = "udp!"; SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024); UInt32 send_size; UInt32 data_size = sizeof(data) - 1; send_size = data_size; // エラーが発生したかどうかチェックする if (error == SFERR_NO_ERROR) { // データを送信する error = _socket.Send(address, data, &send_size); switch (error) { case SFERR_NO_ERROR: // 指定したサイズのデータが書き込まれたかチェックする // Send 関数は指定したサイズのデータを一度に書き込めないことがある // その場合、ここでは簡易化のためエラーとしている if (send_size == data_size) { // データを受信する OnReceive(SFERR_NO_ERROR); } else { TRACE("...send failed..."); } break; case AEE_NET_WOULDBLOCK: // データ送信がブロックされたとき // Send をスケジュールする: OnSend コールバック関数を登録する // ※ OnSend コールバック関数は Send 可能になれば BREW AEE により呼び出される _socket.ScheduleSend(XALLBACK_INTERNAL(OnSend)); break; } } return; } // Receive(データ受信)可能が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnReceive, error) { SFXSocketAddress socket; SFXBuffer buffer; UInt32 receive_size; UInt32 buffer_size(4); // エラーが発生したかどうかチェックする if (error == SFERR_NO_ERROR) { buffer.SetSize(buffer_size); receive_size = buffer_size; // データを受信する error = _socket.Receive(&socket, buffer.GetBuffer(), &receive_size); switch (error) { case SFERR_NO_ERROR: // 指定したサイズのデータが読み込まれたかチェックする // Receive 関数は指定したサイズのデータを一度に読み込めないことがある // その場合、ここでは簡易化のためエラーとしている if (receive_size == buffer_size) { // 読み込んだデータを表示する buffer.SetSize(buffer_size + 1); buffer[buffer_size - 1] = '\0'; TRACE(":%s", SFXAnsiString(buffer).GetCString()); // ソケットを閉じる _socket.Close(); } else { TRACE("...receive failed..."); } break; case AEE_NET_WOULDBLOCK: // データ受信がブロックされたとき // Receive をスケジュールする: OnReceive コールバック関数を登録する // ※ OnReceive コールバック関数は Receive 可能になれば BREW AEE により呼び出される _socket.ScheduleReceive(XALLBACK_INTERNAL(OnReceive)); break; } } return; }
Copyright(c) 2002 - 2024 Sophia Cradle Incorporated All Rights Reserved. |