 C #
- Criando um Chat - Parte 1 - O Cliente
C #
- Criando um Chat - Parte 1 - O Cliente
|  | Neste artigo eu vou mostrar como criar um Chat procurando ser bem objetivo e mantendo as coisas o simples possível. | 
Na verdade uma aplicação de Chat (bate-papo) consiste em duas aplicações:
Para poder acompanhar e entender tudo que vamos fazer é necessário que se tenha conhecimento sobre os seguintes tópicos:
Vamos iniciar criando o cliente.
Chat - Criando a aplicação cliente
A aplicação cliente é a mais simples, já que tudo o que ela tem a fazer é tentar se conectar ao servidor de bate-papo, pedir um nome de usuário, começar a ouvir as mensagens e enviar suas próprias e, finalmente, desligar.
Inicie o Visual C# 2010 Express Edition e crie um novo projeto do tipo Windows Appliation com o nome ChatCliente:
|  | 
Vamos alterar o nome do formulário form1.cs criado por padrão no projeto para frmCliente.cs e a seguir definir o leiaute conforme mostra a figura abaixo no formulário:
|  | Controles usados no
        formulário: 
 | 
Vamos agora ao código do cliente:
1- Namespaces usados:
using
System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System;
2- Declarando as variáveis usadas no projeto:
// Trata o
nome do usuário
private
string NomeUsuario = "Desconhecido";
private StreamWriter stwEnviador;
private StreamReader strReceptor;
private TcpClient tcpServidor;
//
Necessário para atualizar o formulário com mensagens da outra
thread
private
delegate void AtualizaLogCallBack(string strMensagem);
//
Necessário para definir o formulário para o estado
"disconnected" de outra thread
private
delegate void FechaConexaoCallBack(string strMotivo);
private Thread mensagemThread;
private IPAddress enderecoIP;
private bool Conectado;
3- Código do evento Click do botão Conectar que verifica se estamos conectados e inicia a conexão;
|      private void btnConectar_Click(object sender, System.EventArgs e)
        {
            // se não esta conectando aguarda a conexão
            if (Conectado == false)
            {
                // Inicializa a conexão
                InicializaConexao();
            }
            else // Se esta conectado entao desconecta
            {
                FechaConexao("Desconectado a pedido do usuário.");
            }
        } | 
4- Código da rotina IncializaConexao():
|   private void InicializaConexao()
        {
            // Trata o endereço IP informado em um objeto IPAdress
            enderecoIP = IPAddress.Parse(txtServidorIP.Text);
            // Inicia uma nova conexão TCP com o servidor chat
            tcpServidor = new TcpClient();
            tcpServidor.Connect(enderecoIP, 2502);
            // AJuda a verificar se estamos conectados ou não
            Conectado = true;
            // Prepara o formulário
            NomeUsuario = txtUsuario.Text;
            // Desabilita e habilita os campos apropriados
            txtServidorIP.Enabled = false;
            txtUsuario.Enabled = false;
            txtMensagem.Enabled = true;
            btnEnviar.Enabled = true;
            btnConectar.Text = "Desconectado";
            // Envia o nome do usuário ao servidor
            stwEnviador = new StreamWriter(tcpServidor.GetStream());
            stwEnviador.WriteLine(txtUsuario.Text);
            stwEnviador.Flush();
            //Inicia a thread para receber mensagens e nova comunicação
            mensagemThread = new Thread(new ThreadStart(RecebeMensagens));
            mensagemThread.Start();
        } | 
O endereço IP é analisado a partir do TextBox em um objeto IPAddress, e então abrimos uma conexão TCP para esse endereço. A porta é 2502, mas você pode usar qualquer porta disponível. Em seguida, preparar os controles no formulário, desativando alguns e habilitando outros.
Alteramos também a legenda de btnConetar para exibir a mensagem "Desconectado". Através de um Stream, informamos ao servidor o nome de usuário, e imediatamente depois que começamos uma nova thread que chama o método RecebeMensagens() que irá ouvir as mensagens recebidas a partir de agora.
Colocando isso em uma thread separada, a nossa aplicação é totalmente utilizável, enquanto ele está escutando as mensagens do servidor e mantem a conexão ativa.
5- Código da rotina RecebeMensagens
|   private void RecebeMensagens()
        {
            // recebe a resposta do servidor
            strReceptor = new StreamReader(tcpServidor.GetStream());
            string ConResposta = strReceptor.ReadLine();
            // Se o primeiro caracater da resposta é 1 a conexão foi feita com sucesso
            if (ConResposta[0] == '1')
            {
                // Atualiza o formulário para informar que esta conectado
                this.Invoke(new AtualizaLogCallBack(this.AtualizaLog), new object[] { "Conectado com sucesso!" });
            }
            else // Se o primeiro caractere não for 1 a conexão falhou
            {
                string Motivo = "Não Conectado: ";
                // Extrai o motivo da mensagem resposta. O motivo começa no 3o caractere
                Motivo += ConResposta.Substring(2, ConResposta.Length - 2);
                // Atualiza o formulário como o motivo da falha na conexão
                this.Invoke(new FechaConexaoCallBack(this.FechaConexao), new object[] { Motivo });
                // Sai do método
               return;
            }
            // Enquanto estiver conectado le as linhas que estão chegando do servidor
            while (Conectado)
            {
                // exibe mensagems no Textbox
                this.Invoke(new AtualizaLogCallBack(this.AtualizaLog), new object[] { strReceptor.ReadLine() });
            }
        } | 
Um novo leitor dee stream está ligado ao cliente TCP. Ele vai ouvir as mensagens recebidas. Mas antes de tudo, lemos a primeira linha vindo do servidor. O motivo é que sabemos que a primeira linha contém uma resposta nos dizendo se estamos ou não conectados com êxito.
Há duas razões para a conexão falhar: 1: usar um nome de usuário já em uso ou 2: usar Administrador como nome de usuário.
O primeiro caractere da resposta dada pelo servidor nos diz o seguinte:
Quando a conexão falha, lemos também o porquê da falha, que inicia no terceiro caractere da mensagem, já que o primeiro é o número, e o segundo é um caractere de pipe. Por exemplo: 0|Nome de Usuário já está em uso. Assim se o primeiro caractere não é um 1 lemos a cadeia que começa no caractere 3 e termina no final da linha para obter essa informação.
O método this.Invoke(...) chama o formulário para se atualizar. Não podemos atualizar diretamente os elementos do formulário nos mesmos a partir deste método porque ele esta em uma thread distinta (lembre-se nós o chamamos usando ThreadStart ()) e operações entre threads são ilegais.
Finalmente, o loop while (Conectado) continua chamando o método strReceptor.ReadLine() que verifica as mensagens recebidas do servidor.
Em seguida, temos o método que continuamos chamando this.Invoke(...); tudo que ele faz é atualizar o TextBox txtLog com a mensagem mais recente.
6- Código da rotina AtualizaLog
|      private void AtualizaLog(string strMensagem)
        {
            // Anexa texto ao final de cada linha
            txtLog.AppendText(strMensagem + "\r\n");
        } | 
7- Código do evento Click do botão Enviar
|       private void btnEnviar_Click(object sender, System.EventArgs e)
        {
            EnviaMensagem();
        } | 
8- O código evento KeyPress da caixa de texto Mensagem:
|       private void txtMensagem_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Se pressionou a tecla Enter
            if (e.KeyChar == (char)13)
            {
                EnviaMensagem();
            }
        } | 
Para enviar uma mensagem usamos o evento click do botão Enviar ou quando a tecla Enter for pressionada. Nestes casos chamamos a rotina EnviaMensagem() conforme os itens 7 e 8 acima.
9- Código da rotina EnviaMensagem
|    // Envia a mensagem para o servidor
        private void EnviaMensagem()
        {
            if (txtMensagem.Lines.Length >= 1)
            {   //escreve a mensagem da caixa de texto
                stwEnviador.WriteLine(txtMensagem.Text);
                stwEnviador.Flush();
                txtMensagem.Lines = null;
            }
            txtMensagem.Text = "";
        } | 
A rotina EnviaMenagem() apenas verifica se o número de linhas é maior ou igual a 1, e então escreve a linha para a conexão TCP através do objeto StreamWriter. A chamda ao método Flush() garante que as mensagens estão sendo enviadas de imediato.
10 - Código da rotina FechaConexao
|   // Fecha a conexão com o servidor
        private void FechaConexao(string Motivo)
        {
            // Mostra o motivo porque a conexão encerrou
            txtLog.AppendText(Motivo + "\r\n");
            // Habilita e desabilita os controles apropriados no formulario
            txtServidorIP.Enabled = true;
            txtUsuario.Enabled = true;
            txtMensagem.Enabled = false;
            btnEnviar.Enabled = false;
            btnConectar.Text = "Conectado";
            // Fecha os objetos
            Conectado = false;
            stwEnviador.Close();
            strReceptor.Close();
            tcpServidor.Close();
        } | 
Para fechar a conexão chamamos o método FechaConexao e neste código temos que o formulário está sendo trazido de volta para o estado não conectado, e a conexão TCP e os streams estão sendo fechados. Mas o que acontece se o usuário não clicar para desconectar mas apenas fechar o aplicativo enquanto a conexão com o servidor está ativa ?
Nós certamente não queremos deixar a conexão aberta como esta até que ele morra por conta própria. Felizmente existe o evento ApplicationExit que é acionado quando o aplicativo for fechado, e é aí que podemos fechar a nossa conexão. Para tratar este evento vamos alterar o código do construtor do formulário conforme abaixo:
11- Definição do tratamento do evento ApplicationOnExit
|   public frmCliente()
     {
           // Na saida da aplicação : desconectar
         Application.ApplicationExit += new EventHandler(OnApplicationExit);
           InitializeComponent();
   } | 
12- Código do evento OnApplicationExit()
|     // O tratador de evento para a saida da aplicação
        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (Conectado == true)
            {
                // Fecha as conexões, streams, etc...
                Conectado = false;
                stwEnviador.Close();
                strReceptor.Close();
                tcpServidor.Close();
            }
        } | 
O código do evento OnApplicationExit() vai ocorrer quando o usuário fechar o aplicativo diretamente com a conexão ativa e vai verificar se estamos conectados e fechar as conexões e os recursos usados
Pegue a primeira parte do
projeto completo aqui:
 ChatCliente.zip
 ChatCliente.zip
Na segunda parte do artigo irei mostrar a criação do Servidor que irá receber e distribuir as mensagens recebidas: C # - Criando um Chat - Parte 2 - O Servidor (inativo)
"Meus filhinhos , estas coisas vos escrevo, para que não pequeis; e se alguém pecar, temos um advogado para com o Pai, Jesus Cristo, o justo." I João 2:1
Referências: