Windows ソケット : アーカイブ付きソケットの動作

この記事では、CSocket オブジェクト、CSocketFile オブジェクト、および CArchive オブジェクトを組み合わせることによって、Windows ソケットを介したデータの送受信を簡略化する方法について説明します。

記事「Windows ソケット: アーカイブを使用するソケットの例」に、PacketSerialize 関数の説明があります。 PacketSerialize の例のアーカイブ オブジェクトは、MFC の Serialize 関数に渡されるアーカイブ オブジェクトによく似ています。 根本的な違いは、ソケットの場合に、アーカイブが標準の CFile オブジェクト (通常はディスク ファイルに関連付けられる) ではなく、CSocketFile オブジェクトにアタッチされることです。 CSocketFile オブジェクトは、ディスク ファイルに接続するのではなく、CSocket オブジェクトに接続します。

CArchive オブジェクトは、バッファーを管理します。 格納 (送信) アーカイブのバッファーがいっぱいになると、関連する CFile オブジェクトがバッファーの内容を書き出します。 ソケットにアタッチされたアーカイブのバッファーをフラッシュすることは、メッセージを送信することと同じです。 読み込み (受信) アーカイブのバッファーがいっぱいになると、CFile オブジェクトは、バッファーが再び使用可能になるまで読み取りを停止します。

クラス CSocketFile は、CFile から派生しますが、配置関数 (SeekGetLengthSetLength など)、ロック関数 (LockRangeUnlockRange)、GetPosition 関数などの CFile メンバー関数をサポートしません。 CSocketFile オブジェクトの役割は、関連する CSocket オブジェクトに対するバイト シーケンスの読み書きだけです。 ファイルは関係しないため、SeekGetPosition などの操作は意味がありません。 CSocketFile は、CFile から派生するため、通常はこれらのメンバー関数のすべてを継承します。 これを回避するために、CSocketFile でサポートされていない CFile メンバー関数がオーバーライドされ、CNotSupportedException がスローされます。

CSocketFile オブジェクトは、その CSocket オブジェクトのメンバー関数を呼び出して、データを送受信します。

次の図に、通信の両側におけるこれらのオブジェクト間の関係を示します。

CArchive, CSocketFile, and CSocket.
CArchive、CSocketFile、CSocket

一見複雑そうに見えますが、その目的は、ソケットの詳細をユーザー自身が管理しなくて済むようにすることです。 ソケット、ファイル、およびアーカイブを作成してから、データをアーカイブに挿入するか、アーカイブから抽出することによって、データの送受信を開始します。 CArchiveCSocketFile、および CSocket がバックグラウンドで詳細を管理します。

CSocket オブジェクトは、実際には二状態オブジェクトです。非同期状態 (通常の状態) のときもあれば、同期状態のときもあります。 非同期状態では、ソケットは、フレームワークから非同期通知を受信することができます。 ただし、データの受送信などの操作中は、ソケットが同期状態になります。 これは、同期操作が完了するまで、ソケットがそれ以上の非同期通知を受信しないことを意味します。 ソケットがモードを切り替えるため、次のような操作を行うことができます。

void CMySocket::OnReceive(int nErrorCode)
{
   if (0 == nErrorCode)
   {
      CSocketFile file(this);
      CArchive ar(&file, CArchive::load);
      CString str;

      ar >> str;
   }
}

CSocket が 2 つの状態のオブジェクトとして実装されていない場合は、以前の通知を処理している間に、同じ種類のイベントに関する追加の通知を受信する可能性があります。 たとえば、OnReceive の処理中に OnReceive 通知を受け取る可能性があります。 上記のコード フラグメントでは、アーカイブから str を抽出すると、再帰につながる可能性があります。 状態を切り替えることにより、CSocket は、追加の通知を防ぐことで再帰を阻止します。 原則は、通知内に通知を入れないことです。

Note

CSocketFile は、CArchive オブジェクトを含まない (制限付き) ファイルとして使用することもできます。 既定で、CSocketFile コンストラクターの bArchiveCompatible パラメーターは TRUE です。 これは、ファイル オブジェクトがアーカイブで使用するためのものであることを示します。 アーカイブなしでファイル オブジェクトを使用するには、bArchiveCompatible パラメーターに FALSE を渡します。

"アーカイブ互換" モードでは、CSocketFile オブジェクトを使用すると、パフォーマンスが向上し、"デッドロック" の危険性が低減されます。デッドロックは、送信側と受信側の両方のソケットが互いに待機しているか、共通のリソースを待機しているときに発生します。 この状況は、CArchive オブジェクトが CFile オブジェクトと連動するように CSocketFile と連動した場合に発生する可能性があります。 CFile を使用した場合は、アーカイブで、要求したバイト数より少ないバイト数を受信したときに、ファイルの終わりに達したと見なすことができます。 ただし、CSocketFile を使用した場合は、データがメッセージ ベースになり、バッファーに複数のメッセージが含まれている可能性があるため、要求したバイト数より少ないバイト数を受信しても、ファイルの終わりと見なすことができません。 この場合は、CFile を使用した場合と同様にアプリケーションがブロックしません。バッファーが空になるまで、バッファーからのメッセージの読み取りを継続できます。 CArchiveIsBufferEmpty 関数は、このような場合にアーカイブのバッファーの状態を監視するのに役立ちます。

詳細については、「Windows ソケット: アーカイブ付きソケットの使用」を参照してください。

関連項目

MFC における Windows ソケット
CObject::Serialize