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 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