Partilhar via


Windows Sockets: como funcionam soquetes com arquivos mortos

Este artigo explica como um objeto CSocket, um objeto CSocketFile e um objeto CArchive são combinados para simplificar o envio e o recebimento de dados por meio de um Soquete do Windows.

O artigo Soquetes do Windows: exemplo de soquetes usando arquivos apresenta a função PacketSerialize. O objeto de arquivo morto no exemplo PacketSerialize funciona muito como um objeto de arquivo morto passado para uma função de Serialização MFC. A diferença essencial é que, para soquetes, o arquivo é anexado não a um objeto CFile padrão (normalmente associado a um arquivo de disco), mas a um objeto CSocketFile. Em vez de se conectar a um arquivo de disco, o objeto CSocketFile se conecta a um objeto CSocket.

Um objeto CArchive gerencia um buffer. Quando o buffer de um arquivo de armazenamento (envio) estiver cheio, um objeto CFile associado gravará o conteúdo do buffer. Liberar o buffer de um arquivo anexado a um soquete é equivalente a enviar uma mensagem. Quando o buffer de um arquivo de carregamento (recebendo) estiver cheio, o objeto CFile interromperá a leitura até que o buffer esteja disponível novamente.

A classe CSocketFile deriva de CFile, mas não dá suporte a funções de membro CFile, como as funções de posicionamento (Seek, GetLength, SetLength e assim por diante), as funções de bloqueio (LockRange ou UnlockRange) ou a função GetPosition. Tudo o que o objeto CSocketFile deve fazer é gravar ou ler sequências de bytes de ou para o objeto CSocket associado. Como não tem um arquivo envolvido, operações como Seek e GetPosition não fazem sentido. CSocketFile é derivado de CFile, portanto, normalmente herdaria todas essas funções de membro. Para evitar isso, as funções de membro CFile sem suporte são substituídas em CSocketFile para lançar um CNotSupportedException.

O objeto CSocketFile chama funções membro de seu objeto CSocket para enviar ou receber dados.

A figura a seguir mostra as relações entre esses objetos em ambos os lados da comunicação.

CArchive, CSocketFile, and CSocket.
CArchive, CSocketFile e CSocket

A finalidade dessa complexidade aparente é protegê-lo da necessidade de gerenciar os detalhes do soquete por conta própria. Você cria o soquete, o arquivo e o arquivo morto, e, em seguida, começa a enviar ou receber dados inserindo-os no arquivo ou extraindo-os do arquivo morto. CArchive, CSocketFile e CSocket gerenciam os detalhes nos bastidores.

Um objeto CSocket é, na verdade, um objeto de dois estados: às vezes assíncrono (o estado usual) e às vezes síncrono. No estado assíncrono, um soquete pode receber notificações assíncronas da estrutura. No entanto, durante uma operação como receber ou enviar dados, o soquete se torna síncrono. Isso significa que o soquete não receberá mais notificações assíncronas até que a operação síncrona seja concluída. Como ele alterna os modos, você pode, por exemplo, fazer algo semelhante ao que segue:

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

      ar >> str;
   }
}

Se CSocket não for implementado como um objeto de dois estados, talvez seja possível receber notificações adicionais para o mesmo tipo de evento enquanto você estiver processando uma notificação anterior. Por exemplo, você pode receber uma notificação OnReceive durante o processamento de um OnReceive. No fragmento de código acima, extrair str do arquivo morto pode levar à recursão. Ao alternar estados, CSocket impede a recursão impedindo notificações adicionais. A regra geral é sem notificações dentro de notificações.

Observação

Um CSocketFile também pode ser usado como um arquivo (limitado) sem um objeto CArchive. Por padrão, o parâmetro do construtor CSocketFile bArchiveCompatible é TRUE. Isso especifica que o objeto de arquivo é usado com um arquivo morto. Para usar o objeto de arquivo sem um arquivo morto, passe FALSE no parâmetro bArchiveCompatible.

Em seu modo "compatível com arquivamento", um objeto CSocketFile fornece melhor desempenho e reduz o perigo de um "deadlock". Um deadlock ocorre quando os soquetes de envio e recebimento estão esperando uns aos outros ou aguardando um recurso comum. Essa situação poderá ocorrer se o objeto CArchive funcionou com o CSocketFile da maneira como funciona com um objeto CFile. Com CFile, o arquivo morto pode presumir que, se ele receber menos bytes do que o solicitado, o fim do arquivo foi atingido. Com CSocketFile, no entanto, os dados são baseados em mensagens; o buffer pode conter várias mensagens, portanto, receber menos do que o número de bytes solicitados não implica o fim do arquivo. O aplicativo não é bloqueado nesse caso como pode acontecer com CFile, e pode continuar lendo mensagens do buffer até que o buffer esteja vazio. A função IsBufferEmpty em CArchive é útil para monitorar o estado do buffer do arquivo em tal caso.

Para obter mais informações, consulte Soquetes do Windows: usando soquetes com arquivos mortos

Confira também

Windows Sockets em MFC
CObject::Serialize