Windows 套接字:使用存档的套接字的示例

本文演示了使用 CSocket 类的示例。 该示例使用 CArchive 对象通过套接字将数据序列化。 请注意,这不是将文档序列化为文件,也不是将文件序列化为文档。

以下示例说明如何使用存档通过 CSocket 对象发送和接收数据。 该示例旨在使应用程序的两个实例(在同一台计算机上或在网络上的不同计算机上)交换数据。 一个实例发送数据,另一个实例接收并确认该数据。 任何一个应用程序都可以发起交换,并且可充当另一应用程序的服务器或客户端。 以下函数在应用程序的视图类中定义:

void PacketSerialize(long nPackets, CArchive &arData, CArchive &arAck)
{
   BYTE bValue = 0;
   WORD nCopies = 0;

   if (arData.IsStoring())
   {
      CString strText;
      errno_t err;
      unsigned int number;

      for (int p = 0; p < nPackets; p++)
      {
         err = rand_s(&number);
         // if (err == 0)...
         bValue = (BYTE)(number % 256);

         err = rand_s(&number);
         // if (err == 0)...
         nCopies = (WORD)(number % 32000);

         // Send header information
         arData << bValue << nCopies;
         for (int c = 0; c < nCopies; c++)
         {
            // Send data
            arData << bValue;
         }

         strText.Format(_T("Sender sent packet %d of %d (Value = %d, Copies = %d)"),
                        p + 1, nPackets, (int)bValue, nCopies);

         // Send receipt string
         arData << strText;
         arData.Flush();

         // Receive acknowledgment
         arAck >> strText;
         // display it
         DisplayMessage(strText);
      }
   }
   else
   {
      CString strText;
      BYTE bCheck;

      for (int p = 0; p < nPackets; p++)
      {
         // Receive header information
         arData >> bCheck >> nCopies;
         for (int c = 0; c < nCopies; c++)
         {
            // Receive data
            arData >> bValue;
            if (bCheck != bValue)
            {
               AfxMessageBox(_T("Packet Failure"));
            }
         }

         // Receive receipt string and display it
         arData >> strText;
         DisplayMessage(strText);

         strText.Format(_T("Recipient received packet %d of %d (Value = %d, Copies = %d)"),
                        p + 1, nPackets, (int)bValue, nCopies);

         // Send acknowledgment
         arAck << strText;
         arAck.Flush();
      }
   }
}

此示例最重要的一点是,其结构与 MFC Serialize 函数的结构相似。 PacketSerialize 成员函数由包含 else 子句的 if 语句组成。 该函数接收两个 CArchive 引用作为参数:arData 和 arAck。 如果 arData 存档对象设置为用于存储(发送),则执行 if 分支;如果 arData 设置为用于加载(接收),则函数采用 else 分支。 有关 MFC 中的序列化的详细信息,请参阅序列化

注意

假设 arAck 存档对象与 arData 相反。 如果 arData 用于发送,arAck 则用于接收,反之亦然

对于发送,示例函数循环特定次数,每次生成一些随机数据以供演示。 应用程序将从某些来源(如文件)获取真实数据。 arData 存档的插入运算符 (<<) 用于发送三个连续数据块的流:

  • 指定数据性质的“标头”(在本例中,是 bValue 变量的值以及将发送的副本数)

    这两个项都是为本示例随机生成的。

  • 数据的指定副本数。

    内部 for 循环发送 bValue 特定次数

  • 接收方向其用户显示名为 strText 的字符串

对于接收,该函数的操作类似,只是它使用存档的提取运算符 (>>) 从存档中获取数据。 接收应用程序验证其接收的数据,显示最终“已接收”的消息,然后发回一条显示“已发送”的消息,供发送应用程序显示。

在此通信模型中,“已接收”一词(即在 strText 变量中发送的消息)用于在通信的另一端显示,因此,它向接收用户指定已接收到一定数量的数据包。 接收方用类似的字符串回复,上面写着“已发送”,以显示在原始发送方的屏幕上。 收到这两个字符串表明已成功通信。

注意

如果您要编写 MFC 客户端程序来与建立的(非 MFC)服务器通信,则请勿通过存档发送 C++ 对象。 除非服务器是知道你要发送的对象类型的 MFC 应用程序,否则它将无法接收和反序列化对象。 Windows 套接字:字节顺序文章中的一个示例显示了这类通信。

有关详细信息,请参阅 Windows 套接字规范:htonl、htons、ntohl、ntohs。 有关详细信息,另请参阅:

另请参阅

MFC 中的 Windows 套接字
CArchive::IsStoring
CArchive::operator <<
CArchive::operator >>
CArchive::Flush
CObject::Serialize