本文介绍如何组合 CSocket 对象、 CSocketFile 对象和 CArchive 对象,以简化通过 Windows 套接字发送和接收数据。
Windows 套接字:使用存档的套接字示例提供了函数PacketSerialize
。 示例中的 PacketSerialize
存档对象的工作方式非常类似于传递给 MFC 序列化 函数的存档对象。 基本区别在于,对于套接字,存档不会附加到标准 CFile 对象(通常与磁盘文件关联),而是附加到对象 CSocketFile
。 对象 CSocketFile
连接到对象,而不是连接到 CSocket
磁盘文件。
对象 CArchive
管理缓冲区。 存储(发送)存档的缓冲区已满时,关联的 CFile
对象会写出缓冲区的内容。 刷新附加到套接字的存档的缓冲区相当于发送消息。 加载(接收)存档的缓冲区已满时,对象 CFile
将停止读取,直到缓冲区再次可用。
类CSocketFile
派生自 CFile
,但它不支持 CFile 成员函数,例如定位函数(Seek
、GetLength
等SetLength
)、锁定函数(LockRange
、或UnlockRange
GetPosition
函数)。
所有 CSocketFile 对象都必须对关联CSocket
对象写入或读取字节序列。 由于文件不涉及,因此此类Seek
GetPosition
作毫无意义。
CSocketFile
派生自 CFile
,因此它通常会继承所有这些成员函数。 为防止这种情况,将重写CSocketFile
不受支持的CFile
成员函数以引发 CNotSupportedException。
该 CSocketFile
对象调用其 CSocket
对象的成员函数来发送或接收数据。
下图显示了通信双方的这些对象之间的关系。
CArchive、CSocketFile 和 CSocket
这种明显的复杂性的目的是保护你免受自己管理套接字细节的必要性。 创建套接字、文件和存档,然后通过将其插入到存档或从存档中提取数据开始发送或接收数据。 CArchive、 CSocketFile 和 CSocket 管理后台的详细信息。
对象 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 套接字:将套接字与存档配合使用