<< Voltar Índice Próxima >>

CLIENTE

O código do cliente possui muitas semelhanças com o do servidor, por isso mesmo este tutorial será pequeno.

#include "MessageIdentifiers.h"
#include "RakNetworkFactory.h"
#include "RakPeerInterface.h"
#include "RakNetStatistics.h"
#include "RakNetTypes.h"
#include "BitStream.h"
#ifdef _WIN32
#include <conio.h>
#include <windows.h> // Sleep
#else
#include "../Unix/kbhit.h"
#include <unistd.h> // usleep
#endif

#include "stdafx.h"
#include "Thread.h"

#define MAX(A,B) (((A)>=(B))? (A) :(B))
#define MIN(A,B) (((A)<=(B))? (A) :(B))

 

Inicialmente adicionamos os includes no arquivo "AplicationListener.h". Também será utilizada uma thread para esperar as conexões, dessa forma precisaremos incluir "Thread.h". As duas últimas linhas serão necessárias para um random no momento da conexão com o servidor.

class AplicationListener : public FrameListener, public OIS::KeyListener,
    public OIS::MouseListener, public OIS::JoyStickListener, public CThread

 

Não se esqueça de incluir entre as classes que "AplicationListener" herdará a que contém a Thread, para isso coloque "public CThread", como está no código acima.

    RakPeerInterface *client;
    char message2[2048], msgRecebida[2048];
    Packet *p;
    std::string name, message;
    int codigo, porta;
    unsigned char packetIdentifier;
    SystemAddress clientID;

 

Ainda no arquivo "AplicationListener.h", adicione as variáveis que utilizaremos.

    //necessario para iniciar o random adequadamente
    srand( time(NULL) );

    //inicia variaveis da raknet
    client = RakNetworkFactory::GetRakPeerInterface();
    client->InitializeSecurity(0, 0, 0, 0);
    clientID = UNASSIGNED_SYSTEM_ADDRESS;
    SocketDescriptor socketDescriptor(random(2000,2010),0);
    client->Startup(1,30,&socketDescriptor, 1);

 

No método "AplicationListener" no arquivo "AplicationListener.cpp", inicializamos o cliente. Começando pela função "srand()" onde o parâmetro será uma referêncial para a randomização, como o tempo do computador está sempre variando, então este é um ótimo referência.

Criamos um cliente com a função "GetRakPeerInterface()", em seguida o método "InitializeSecurity()" pode ser usado para definir uma segurança a mais na conexão com chaves públicas e privadas. Com "socketDescriptor()" define-se a porta que o cliente irá escutar as informações vindas do servidor. Ela será randomizada pelo fato de que normalmente testa-se 2 clientes e 1 servidor na mesma máquina, e para evitar o problema(erro) de dois clientes estarem usando uma mesma porta, ela será escolhida aleatoriamente entre as de número 2000 e 2010.

O método "Startup()" inicia o cliente, onde o primeiro parâmetro é a quantidade de conexões por ele suportada, no caso apenas uma que é com o servidor. O segundo é o tempo em milisegundo que a thread que espera as conexões irá dormir(sleep). O terceiro é o socketDescriptor que contém a porta da conexão e o quarto o número de socketDescriptors utilizados.

int AplicationListener::random(int a, int b){
   return ( MIN(a,b) + rand()%(MAX(a,b)-MIN(a,b)));
}

 

O método "random()" acima deve ser acrescentado entre os outros da classe "AplicationListener".

case OIS::KC_C:
    //conecta o cliente ao servidor
    client->Connect("127.0.0.1", atoi("1000"), "Irado", (int) strlen("Irado"));

    //começa a thread para espera de recebimento de dados
    this->Start();
    break;

 

O cliente conecta-se com o servidor através do método "Connect()". O parâmetro de número um, é o endereço IP ou o nome(DNS) do servidor, no exemplo ele irá se conectar no servidor localmente na máquina(localhost). O segundo é a porta a qual ele irá se conectar. O terceiro é a senha para se conectar ao servidor e o quarto o comprimento da string da senha. Depois com a função "Start()" inicia a execução da thread que irá esperar os dados vindos do servidor.

DWORD AplicationListener::Run( LPVOID )
{
    while (true)
    {
    	//Sleep necessario para evitar q o programa utilize os 100%
        //continuamente da cpu
        #ifdef _WIN32
            Sleep(30);
        #else
            usleep(30 * 1000);
        #endif

        p = client->Receive();
        if (p!=0) { identificaPacote(); }
    }

    return true;
}

 

Alguns dos demais métodos são semelhantes ao do código do servidor, como o "Run" da thread.

unsigned char AplicationListener::GetPacketIdentifier(Packet *p)
{
    if (p==0)
        return 255;

    if ((unsigned char)p->data[0] == ID_TIMESTAMP)
    {
        assert(p->length > sizeof(unsigned char) + sizeof(unsigned long));
        return (unsigned char) p->data[sizeof(unsigned char) + sizeof(unsigned long)];
    }
    else
        return (unsigned char) p->data[0];
}

 

O método "GetPacketIdentifier()" também é igual ao do servidor.

void AplicationListener::identificaPacote(void)
{
	packetIdentifier = GetPacketIdentifier(p);

	switch (packetIdentifier)
	{
		case ID_DISCONNECTION_NOTIFICATION:
			 break;

		default:

			codigo = atoi(strtok((char*)p->data,"&"));

			switch (codigo)
			{
			case 2:
				strcpy(msgRecebida, strtok(NULL,"&"));
				break;

			}

		}

	// Deleta o pacote e libera memória
	client->DeallocatePacket(p);

}

 

Apenas "identificaPacote()" se difere um pouco, mas a idéia básica é a mesma.

Italo Mendes
italo.ribeiro@gmail.com

<< Voltar Índice Próxima >>