18 de dezembro de 2009

Comunicação entre processos : Sockets - Client

No último post, mostrei como construir um Serviço usando um Socket servidor para monitorar requisições de Clients que conheçam a sintaxe apropriada para se comunicar com esse Serviço. No caso, apenas uma mensagem foi implementada no Servidor e ela retorna uma lista de Certificados Digitais instalados no computador onde o Serviço está em execução. Neste post, mostro a outra ponta da implementação, isto é, como construir um Client capaz de se comunicar com esse Servidor e obter a tal lista.

Para a aplicação Client poder se conectar com o Serviço, ela tem que configurar uma instância do componente TClientSocket, informando nela tanto o endereço do servidor quanto a porta que ele está monitorando. Depois, enviar uma mensagem com a solicitação desejada e aguardar a resposta.
_StatusMens = 0; /* Status da mensagem */
_MemorySize = 0;
_Memory->Clear ();
_ClientSocket->Port = 1024;
_ClientSocket->Host = "PC_151";

aguarde ("Obtendo certificados");
try {
_ClientSocket->Active = true;

/* Aguarda conectar */
while (!_ClientSocket->Active && _StatusMens == 0)
Application->ProcessMessages ();

if (_ClientSocket->Active)
{
_ClientSocket->Socket->SendText ("#GET_CERTIFICATE");

/* Aguarda retorno */
while (_StatusMens == 0)
Application->ProcessMessages ();
}

if (_Status < 0)
col_erro ("Não foi possível obter certificados.");

_ClientSocket->Active = false;
}
__finally {
fim_aguarde ();
}

Note no trecho reproduzido acima que é possível especificar o Host pelo nome, o que é recomendado principalmente se o IP do Servidor for variável. Note também que após a conexão há um laço para aguardar o retorno. Isso é necessário porque a resposta do Servidor não é síncrona, isto é, a função que envia mensagens não recebe o retorno enviado pelo Servidor. Aqui, o Client envia o texto "#GET_CERTIFICATE". Estes caracteres representam para o meu Serviço o nome do comando que deve retornar os certificados existentes no Servidor. Obviamente, esse nome foi estabelecido por mim quando o Serviço foi projetado e o Client deve saber dessa informação de antemão para poder submeter corretamente a requisição.

Para o Client receber o retorno, é preciso responder ao evento OnRead do TClientSocket e ir lendo os bytes enviados em blocos pelo Servidor. Portanto, o OnRead pode ser executado mais de uma vez antes que a resposta toda seja recebida:
void __fastcall TFrmCert::ClientSocketRead(TObject *Sender, TCustomWinSocket *Socket)
{
char *lBuffer = NULL;
int lLen = Socket->ReceiveLength();

if (lLen > 0)
{
lBuffer = new char [lLen];

try {
/* Guarda no buffer interno os bytes recebidos */
Socket->ReceiveBuf ((void *)lBuffer, lLen);

if (memcmp (lBuffer, "#CERTIFICATE_ERROR", 18) == 0)
_StatusMens = -1;
else
{
/* Primeiro bloco recebido ? Então recupera o tamanho total do retorno enviado pelo servidor */
if (_MemorySize == 0)
memmove (&_MemorySize, lBuffer, sizeof (_MemorySize));

{ Guarda no Memory stream todo o buffer recuperado. Cada bloco lido é acrescentado ao fim do último bloco até receber a mensagem toda. }
_Memory->Write (lBuffer, lLen);

{ Recebeu todos os blocos ? }
if (_Memory->Size == (_MemorySize + (int) sizeof (_MemorySize)))
_StatusMens = 1;
}
}
__finally {
delete [] lBuffer;
}
}
}

A leitura do retorno mostrada acima é automaticamente executada numa thread separada e é por isso que no trecho anterior há o laço de aguarde logo após o envio da requisição. Aquele código monitora a variável que controla o status da recepção. Mudanças no valor do status sinalizam que a recepção foi concluída - ou, se for o caso, que um erro ocorreu. após o término do laço e se não houve erro, a variável stream _Memory conterá todos os bytes enviados pelo Servidor. O Client, então, poderá tratar esse conteúdo da forma que julgar necessário, baseado no conhecimento prévio sobre o significado dos bytes retornados.

Se você estabelecer que o seu Servidor receberá solicitações em um formato XML bem definido, contendo tags com o nome de função a ser chamada e os parâmetros a serem supridos, você terá uma versão sua simplificada do conceito de WebServices.

Nenhum comentário :

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.