Windows Sockets: Ejemplo de sockets que usan archivos

En este artículo se presenta un ejemplo de uso de la clase CSocket. En el ejemplo se emplean objetos CArchive para serializar los datos a través de un socket. Tenga en cuenta que esto no es la serialización de documentos en o desde un archivo.

En el ejemplo siguiente se muestra cómo se usa el archivo para enviar y recibir datos a través de objetos CSocket. El ejemplo está diseñado para que dos instancias de la aplicación (en el mismo equipo o en máquinas diferentes de la red) intercambien datos. Una instancia envía datos, que la otra instancia recibe y confirma. Cualquiera de las aplicaciones puede iniciar un intercambio y puede actuar como servidor o como cliente para la otra aplicación. La siguiente función se define en la clase de vista de la aplicación:

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();
      }
   }
}

Lo más importante de este ejemplo es que su estructura es paralela a la de una función Serialize de MFC. La función miembro PacketSerialize consta de una instrucción if con una cláusula else. La función recibe dos referencias CArchive como parámetros: arData y arAck. Si el objeto de archivo arData se establece para almacenar (enviar), se ejecuta la rama if; de lo contrario, si arData se establece para cargar (recibir), la función toma la rama else. Para más información sobre la serialización en MFC, consulte el artículo Serialización.

Nota:

Se supone que el objeto de archivo arAck es el opuesto de arData. Si arData sirve para enviar, arAck recibe, y al contrario.

Para enviar, la función de ejemplo se repite durante un número especificado de veces, cada vez que se generan algunos datos aleatorios con fines de demostración. La aplicación obtendrá datos reales de un origen, como un archivo. El operador de inserción del archivo arData (<<) se usa para enviar una secuencia de tres fragmentos consecutivos de datos:

  • Un "encabezado" que especifica la naturaleza de los datos (en este caso, el valor de la variable bValue y el número de copias que se enviarán).

    Ambos elementos se generan aleatoriamente para este ejemplo.

  • El número especificado de copias de los datos.

    El bucle interno for envía bValue el número de veces especificado.

  • La cadena denominada strText que el receptor muestra a su usuario.

Para recibir, la función se ejecuta de forma similar, salvo que usa el operador de extracción del archivo (>>) para obtener datos del archivo. La aplicación receptora comprueba los datos que recibe, muestra el mensaje "Recibido" final y, a continuación, devuelve un mensaje que indica "Enviado" para que se muestre en la aplicación de envío.

En este modelo de comunicaciones, la palabra "Recibido", el mensaje enviado en la variable strText, es para mostrarse al otro extremo de la comunicación, por lo que especifica al usuario receptor que se ha recibido un determinado número de paquetes de datos. El receptor responde con una cadena similar que dice "Enviado", para que se muestre en la pantalla del remitente original. La recepción de ambas cadenas indica que se ha producido una comunicación correcta.

Precaución

Si está escribiendo un programa cliente de MFC para comunicarse con servidores establecidos (que no sean MFC), no envíe objetos de C++ mediante el archivo. A menos que el servidor sea una aplicación MFC que comprenda los tipos de objetos que quiere enviar, no podrá recibir ni deserializar los objetos. En un ejemplo del artículo Windows Sockets: orden de bytes se muestra una comunicación de este tipo.

Para más información, vea la especificación de Windows Sockets: htonl, htons, ntohl, ntohs. Además, para más información, consulte:

Consulte también

Windows Sockets en MFC
CArchive::IsStoring
CArchive::operator <<
CArchive::operator >>
CArchive::Flush
CObject::Serialize