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成员函数由包含子ifelse句的语句组成。 该函数接收两个 CArchive 引用作为参数: arDataarAck。 如果为存储(发送)设置了 arData 存档对象,则 if 分支将执行;否则,如果将 arData 设置为加载(接收),该函数将获取 else 分支。 有关 MFC 中的序列化的详细信息,请参阅 序列化

注释

arAck 存档对象假定与 arData 相反。 如果 arData 用于发送, 则 arAck 接收,反之则为 true。

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

  • 一个指定数据性质的“标头”(在本例中, bValue 变量的值和将发送的副本数)。

    此示例会随机生成这两个项。

  • 数据的指定副本数。

    内部 for 循环发送 bValue 指定的次数。

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

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

在此通信模型中,在 strText 变量中发送的消息“Received”一词用于在通信的另一端显示,因此它向接收用户指定已接收特定数量的数据包。 接收方使用类似于“Sent”的字符串进行答复,以便在原始发件人的屏幕上显示。 收到这两个字符串表示已成功通信。

谨慎

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

有关详细信息,请参阅 Windows 套接字规范: htonlhtonsntohlntohs。 此外,有关详细信息,请参阅:

另请参阅

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