SUJA e seus CLIENTES

Detalhes técnicos e RECEITA

SUJA é um servidor para jogos - se você é programador BUILDER há aqui uma descrição de como usá-lo e programá-lo (no final da página)

 Links

SUJA
MSG CLIENTE para SUJA com fonte - feito no Builder 3 com componentes (prontos) do Builder
MSG Cliente com fonte - feito no Builder 4 sem usar os componentes de Internet

Explicação dos programas acima:

SUJA_TCP_msg_server_com_VCLcomponentes
SUJA é um servidor que repete as mensagens recebidas por ele para todos os clientes conectados.
A idéia é deixar todo trabalho de tratamento de erros e recepção/filtragem de mensagens com os "programas clientes".
Foi feito no Builder 3 porque nesta versão gratuita tinha componentes capaz de executar essa tarefa. Na verdade é uma adapatação de programas exemplos, tentei manter o mais simples possível, sem alterar muito o código, já que o servidor precisa ser "universal". parte do código eu aproveitei/traduzi do ConnecteInternet.cpp em

ftp://ftp-developpez.com/c/sources/bcb/codes/connecteinternet.zip

My_TCP_Message_Client
Os clientes (My_TCP_Message_Client) foram criados no Builder 3 com uso dos componentes de Internet da Borland ou no Builder 4 sem a utilização de componentes específicos do Builder, já que eles não tinham nenhum na versão gratuita...
A idéia é que ao conectar e enviar mensagens, cada cliente conectado recebas as mensagens enviadas. Com isso é possível construir programas que comuniquem-se uns com os outros. O problema desta estratégia é que os programas clientes poderão ser programados para "trapacear", já que o controle não sera feito pelo servidor. essa estratégia, entretanto, garante menos "carga" para o servidor SUJA, que não terá muitas tarefas a executar.

A mensagem que chega precisará ser filtrada: sempre chega a mensagem encabeçada pelo número de IP
Só pode haver um cliente por máquina a não ser que use portas diferentes;
também nada impede que haja mais de um servidor usando portas diferentes;

Como usar: Inicie o SUJA (servidor) em um dos computadores da rede e veja o IP da máquina. Inicie a escuta. A seguir, em outros computadores da rede, rode os clientes, fornecendo o número da porta escolhida e o endereço de IP que o servidor SUJA detectou. Ao enviar uma mensagem qualquer pelos clientes, todos os outros clientes conectados recebem a mensagem e o número do IP da máquina que o enviou.

Caberia aos clientes detectar as mensagens que são para si, além de limpar a mensagem, deixando apenas a parte de texto.

A seguir, como foi programado o SUJA:

SUJA - Servidor Universal para Jogos Amadores

(usando o Borland C++ Builder 3)

Obs.: Utilizei o Builder 3 porque na minha versão gratuita é a que tinha a palete "Internet" com o ServerSocket. Qualquer versão que tenha a palete Internet instalada deve funcionar, provavelmente, mas neste caso, como este servidor será usado para *muitos* outros projetos, deixarei um executável compilado e disponível sem nenhum custo para os usuários (registrados ou não) do meu site "Receitas para Programadores".

Obs.: parte do código eu aproveitei/traduzi do ConnecteInternet.cpp em  ftp://ftp-developpez.com/c/sources/bcb/codes/connecteinternet.zip


Ingredientes

1 Form

6 Label

1 ListBox

4 Edit

3 Button

1 Status Bar

1 ServerSocket


Mode de preparo:

Coloque os componentes adequadamente dentro do Form1.

A seguir dê um duplo clique em cada um dos componentes abaixo listados, introduzindo o código colorido mostrado abaixo:

Button1:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ServerSocket1->Port=StrToInt(Edit1->Text);
    ServerSocket1->Open();
    Button1->Enabled=false;
    Button2->Enabled=true;
    StatusBar1->SimpleText="Server Started! Listening ...";
    Edit4->Text=IntToStr(ServerSocket1->Socket->ActiveConnections);
}

Button2:

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ServerSocket1->Close();
    Button1->Enabled=true;
    Button2->Enabled=false;
    StatusBar1->SimpleText="Server Stopped!";
    Edit4->Text=IntToStr(ServerSocket1->Socket->ActiveConnections);
}

Button3:

void __fastcall TForm1::Button3Click(TObject *Sender)
{
   AchaIP();
}

Form:

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    AchaIP();
}

ServerSocket1:

void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
      StatusBar1->SimpleText="Connected from "+Socket->RemoteAddress;
      Edit4->Text=IntToStr(ServerSocket1->Socket->ActiveConnections);
}

void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
     Edit4->Text=IntToStr(ServerSocket1->Socket->ActiveConnections-1);
     StatusBar1->SimpleText="Disconnected from"+Socket->RemoteAddress;  
}

void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
    char buffer[256];
    int len;
    AnsiString Message;
    int i;

    // Receive message
    len=Socket->ReceiveBuf(buffer,255);
    buffer[len]=0;
    Edit2->Text=StrPas(buffer);
    Edit3->Text=Socket->RemoteAddress;
    StatusBar1->SimpleText=IntToStr(len)+" bytes received!";

    // Broadcast received message to all connected clients
    Message=Socket->RemoteAddress+": "+StrPas(buffer);
    strcpy(buffer,Message.c_str());
    for(i=0;i<ServerSocket1->Socket->ActiveConnections;i++)
   ServerSocket1->Socket->Connections[i]->SendBuf(buffer,strlen(buffer));
}

 

Modifique a propriedade Caption do form e dos componentes (botões e labels) e limpe a propriedade Text de cada Edit conforme a imagem:

Labels:

Label1

Port Number:

Label2

Message:

Label3

From:

Label4

Connections:

Label5

Esta Maquina:

Label6

IP: 0.0.0.0

Buttons

Button1

Start

Button2

Stop

Button3

Detectar IP

Propriedade Text de cada Edit

Edit1

4001

Edit2

[vazio]

Edit3

[vazio]

Edit4

0

 

Você ainda precisará acrescentar dois métodos no arquivo ".h" da sua Unit (no meu caso o arquivo de header chamava-se SUJAUnit.h)

class TForm1 : public TForm
{
__published: // IDE-managed Components
    TLabel *Label1;
    TLabel *Label2;
    TLabel *Label3;
    TLabel *Label4;
    TEdit *Edit1;
    TStatusBar *StatusBar1;
    TEdit *Edit2;
    TEdit *Edit3;
    TButton *Button1;
    TButton *Button2;
    TEdit *Edit4;
    TServerSocket *ServerSocket1;
    TButton *Button3;
    TLabel *Label5;
    TLabel *Label6;
    TListBox *ListBox1;
    void __fastcall ServerSocket1ClientConnect(TObject *Sender,
          TCustomWinSocket *Socket);
    void __fastcall ServerSocket1ClientDisconnect(TObject *Sender,
          TCustomWinSocket *Socket);
    void __fastcall ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket);
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall Button2Click(TObject *Sender);
    void __fastcall Button3Click(TObject *Sender);
   
    void __fastcall FormCreate(TObject *Sender);
private: // User declarations
    void AchaIP(void);
    int VerConex(void);

public:  // User declarations
    __fastcall TForm1(TComponent* Owner);
};

e no código da Unit ainda acrescentar:

int TForm1::VerConex(void)
{
    int conectada=0;
    typedef BOOL (WINAPI *PF_INETGETCONNECTEDSTATE)(LPDWORD, DWORD);
    HANDLE hWinInet;
    PF_INETGETCONNECTEDSTATE pfInternetGetConnectedState;
    //.............
    hWinInet = LoadLibrary("WININET.DLL");  //Chargement de la dll
    if(hWinInet == NULL)
    {
         Label5->Caption = "Impossivel carregar Wininet.dll";
         return conectada;
    }
    pfInternetGetConnectedState = (PF_INETGETCONNECTEDSTATE) GetProcAddress(
                          hWinInet, "InternetGetConnectedState");
                // affectation du pointeur sur la fonction
    if(pfInternetGetConnectedState == NULL)
    {
         Label5->Caption = "Erro chamando função InternetGetConnectedState";
         if(hWinInet) FreeLibrary(hWinInet);
         return conectada;
    }
    //.............
    DWORD TypeCon ;
    if (pfInternetGetConnectedState(&TypeCon, 0)) //appel de la fonction
    {
        Label5->Caption = "Conectado";
        conectada=1;
    }
    else
    {
        Label5->Caption = "Não Conectado";
        conectada=0;
    }
    //.............
    if(hWinInet) FreeLibrary(hWinInet); //libération de la dll
    //.............
    return conectada;
}

// --------------------------------------------
// --------------------------------------------
void TForm1::AchaIP(void)
{
    // para achar IP:
      WORD wVersionRequested;
      WSADATA wsaData;
      char name[255];
      AnsiString ip;
      PHOSTENT hostinfo;
      wVersionRequested = MAKEWORD( 1, 1 );

    if(WSAStartup( wVersionRequested, &wsaData ) == 0 && VerConex()==1)
    {
        if( gethostname ( name, sizeof(name)) == 0)
        {
              Label5->Caption = "Esta máquina: ";
              Label5->Caption = Label5->Caption + name;  //nom de l'ordinateur
              if((hostinfo = gethostbyname(name)) != NULL)
              {
                   ip = inet_ntoa (*(in_addr *)*hostinfo->h_addr_list);
                   Label6->Caption = "IP: " + ip;  //adresse IP
                    ////////// novo/
                    ListBox1->Items->Clear();
                    for (int i = 0; hostinfo->h_addr_list[i] != 0; ++i)
                    {
                        struct in_addr addr;
                        memcpy(&addr, hostinfo->h_addr_list[i], sizeof(struct in_addr));
                        ListBox1->Items->Add((String)inet_ntoa(addr));
                    }
                    ListBox1->Items->Add("127.0.0.1");
                    ////////// fim novo/
              }
        }
        WSACleanup( );
    }
    else
    {
        ListBox1->Items->Clear();
        ListBox1->Items->Add("127.0.0.1");
    }
}

Em breve instruções para programação de CLIENTES que usem o SUJA (por enquanto use os arquivos fornecidos para entender seu funcionamento)


Copyright  Victor M. Sant'Anna  2007