Windows 套接字:使用存档的套接字如何工作

本文介绍如何组合 CSocket 对象、 CSocketFile 对象和 CArchive 对象,以简化通过 Windows 套接字发送和接收数据。

Windows 套接字:使用存档的套接字示例介绍了PacketSerialize函数。 示例中的 PacketSerialize 存档对象的工作方式非常类似于传递给 MFC 序列化 函数的存档对象。 基本区别在于,对于套接字,存档不会附加到标准 CFile 对象(通常与磁盘文件关联),而是附加到对象 CSocketFileCSocketFile 对象会连接到 CSocket 对象,而不是连接到磁盘文件。

对象 CArchive 管理缓冲区。 存储(发送)存档的缓冲区已满时,关联的 CFile 对象会写出缓冲区的内容。 刷新附加到套接字的存档缓冲区相当于发送消息。 加载(接收)存档的缓冲区已满时,对象 CFile 将停止读取,直到缓冲区再次可用。

CSocketFile派生自 CFile,但它不支持 CFile 成员函数,例如定位函数(SeekGetLengthSetLength)、锁定函数(LockRange、或UnlockRangeGetPosition函数)。 所有 CSocketFile 对象都必须对关联CSocket对象写入或读取字节序列。 由于没有涉及文件,因此诸如SeekGetPosition的操作毫无意义。 CSocketFile 派生自 CFile,因此它通常会继承所有这些成员函数。 若要防止这种情况,请在 CFile 中替代不受支持的 CSocketFile 成员函数以引发 CNotSupportedException

CSocketFile 对象调用其 CSocket 对象的成员函数来发送或接收数据。

下图显示了通信双方的这些对象之间的关系。

CArchive、CSocketFile 和 CSocket。
CArchive、CSocketFile 和 CSocket

这种明显复杂性的目的是使你无需自己管理套接字的细节。 创建套接字、文件和存档,然后通过将其插入到存档或从存档中提取数据开始发送或接收数据。 CArchiveCSocketFileCSocket 管理后台的详细信息。

对象 CSocket 实际上是一个双状态对象:有时是异步(通常状态),有时是同步的。 在异步状态下,套接字可以从框架接收异步通知。 但是在接收或发送数据等操作期间,套接字会变为同步状态。 这意味着,在同步操作完成之前,套接字不会接收进一步的异步通知。 因为它可以切换模式,因此您可以执行以下操作:

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

      ar >> str;
   }
}

如果 CSocket 不是作为双状态对象实现,则在处理以前的通知时,可能会收到有关相同类型事件的额外通知。 例如,您在处理OnReceive时可能会收到OnReceive通知。 在上面的代码片段中,从存档中提取 str 可能会导致递归。 通过切换状态, CSocket 通过阻止其他通知来防止递归。 一般规则是通知中没有通知。

注释

还可以将 A CSocketFile 用作没有 CArchive 对象的(有限)文件。 默认情况下, CSocketFile 构造函数的 bArchiveCompatible 参数为 TRUE。 这指定文件对象用于存档。 若要在没有存档的情况下使用文件对象,请将 FALSE 传入 bArchiveCompatible 参数。

在“存档兼容”模式下,CSocketFile 对象提供更好的性能,并减少“死锁”的危险。当发送和接收套接字相互等待或等待常见资源时,会发生死锁。 如果 CArchive 对象使用对象 CSocketFile 的方式处理 CFile 对象,则可能会出现这种情况。 使用 CFile,归档可以假定如果接收到的字节数少于请求的字节数,则已到达文件的末尾。 但是,数据 CSocketFile基于消息;缓冲区可以包含多个消息,因此接收的字节数少于请求的字节数并不意味着文件结束。 在这种情况下,应用程序不会像可能发生在 CFile 时那样阻塞,并且它可以继续从缓冲区读取消息,直到缓冲区为空。 IsBufferEmpty 函数CArchive可用于监视存档缓冲区在此类情况下的状态。

有关详细信息,请参阅 Windows 套接字:将套接字与存档配合使用

另请参阅

MFC 中的 Windows 套接字
CObject::Serialize