Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Micilini Roll

[Resolvido] [Puzzle] Chat Privado (WebSockets + PHP Sockets)

Recommended Posts

Fala galera, estou aqui para pedir a ajuda de todos voces. Tudo que iremos tentar fazer é criar um chat privado utilizando websockets junto ao php sockets, para adiantar algumas coisas eu ja fiz um chat e disponibilizei no github, voces podem acessar atraves do link abaixo:

 

 

Esse chat funciona perfeitamente, mas no entanto ele é um chat global, ou seja, uma mensagem enviada por um usuario X, vai para todos os usuarios que estão na sala do chat. Como dito anteriormente a nossa ideia é criar um chat privado, então vamos a algumas considerações:

 

  • No meu caso estou utilizando os arquivos dentro da pasta easychat (que esta no link enviado anteriormente)
  • Podemos utilizar node.js, socket.io e afins? Não, estou querendo resolver somente com php e javascript puro.

 

Agora chegou a hora de dar uma pincelada no meu codigo:

 

Aplicacao.js

 

Existem duas funções responsaveis por enviar e receber a mensagem do servidor e abaixo estão elas:

form.onsubmit = function(e) { e.preventDefault(); // Recuperando a mensagem do textarea.
var mensagem = mensagemTexto.value; // Enviando a mensagem através do WebSocket.
socket.send(mensagem); // Adicionando a mensagem numa lista de mensagens enviadas.
listaMensagem.innerHTML += '<li class="envia"><span>Enviado:</span>' + mensagem + '</li>'; // Limpando o campo da mensagem após o envio.
mensagemTexto.value = ''; return false;
};


socket.onmessage = function(event) {
var mensagem = event.data; listaMensagem.innerHTML += '<li class="recebida"><span>Recebida:</span>' + mensagem + '</li>';
};

Quando enviamos uma mensagem ele executa o comando socket.send(mensagem) ali eu pensei em enviar mais alguns parametros como:

 

  • IP do usuario (Pode precisar)
  • Chat de onde ele esta acessando (Chat1, Chat2, Chat3)
  • Mensagem (é claro rs)

 

Já no lado do PHP, o comando abaixo é responsavel por pegar a resposta do usuario e retorna-la de volta:

 

Server.php

 }else{
$bytes = socket_recv($sock, $data, 2048, null);
$d = unmask($data);
foreach ($cls as $socket) {
if($socket != $m_sock && $val > 0){
try{
socket_write($socket,(encode($d)));
}catch(Exception $e){
unset($cls[$socket]);
socket_close($cls[$socket]);
}
}
}
}
} 

Com o comando socket_recv ele consegue captar a mensagem que esta sendo enviada e realiza a função unmask nela, um pouco mais adiante ele faz o encode desta mensagem que recebeu e envia de volta para aquele socket (e todos que estão conectados naquele socket recebem a mensagem).

 

Nesse caso, como nosso chat é privada devemos pensar tambem em fazer o insert e em seguida um select no banco de dados, entao melhor maneira de fazer isso é inserindo esses comandos entre os codigos try e socket_write, então vamos aos testes:

......

try{

//Aqui estabilizamos uma conexão com o banco de dados  e inserimos na tabela a mensagem + ip + data + Chat1 (ou 2 ou 3).

socket_write($socket,(encode($d)));
}

.....

Acho que tambem seria melhor criar um campo no banco de dados para verificar se a mensagem foi visualizada ou não?

 

Depois que inserimos no banco de dados chegou a hora do puzzle:

 

Como iremos fazer para retornar a mensagem para aquele determinado usuario?

 

Antes de respondermos a esta pergunta vamos criar um cenario novo e de simples visualização para todos nos:

 

  • Vamos criar um arquivo php com 2 links: Ir para o Chat 1 & Ir para o Chat 2
  • Vamos reaproveitar aqueles arquivos dentro da pasta EasyChat
  • Vamos duplicar o arquivo index.php, criando indexChat1.php e IndexChat2.php

 

Ambos os indexs irão utilizar a porta 8080 (assim como esta no github), Não! nos não iremos separar os chats em portas diferentes (tenha em mente que isso é so um teste para realizar algo mais completo lá na frente, IMAGINE 10000 chats privados acontecendo simultaneamente e abrimos uma porta para cada um deles......).

 

Entao apartir deste momento temos 2 indexes diferentes utilizando os mesmos arquivos: aplicacao.js e server.php, no caso do arquivo aplicacao.js ele envia valores diferentes para o socket php como ip, mensagem e o tipo de chat que ele esta inserido, como chat1 ou chat 2.

 

Executandos os Testes

 

OK, vamos abrir o arquivo indexChat1.php em uma aba, e indexChat2.php em outra aba do nosso navegador, vamos inicialmente escrever uma mensagem no chat1, quando fizermos isso (e do jeito que nosso codigo atualmente esta), a mensagem será recebida tambem na aba do chat2, e a mesma coisa aconteceria caso digitarmos algo no chat2.

 

Mas pelo menos no banco de dados esta dá seguinte forma:

 

ID = 0

IP = 32.22.221.22

Local = Chat1

Mensagem = Olá mundo

Data = 01/01/2016

Visualizado = false

 

Agora voltamos a seguinte pergunta: Como iremos fazer para os usuarios que estão no chat1, nao receber e nem enviar mensagens para os usuarios que estão no chat2 e virce-versa?

 

Eu acredito que a resposta esta na criação de um codigo que ainda nao sabemos mas que deve ser colocado dentro do arquivo server.php mais especificamente entre os comandos try e socket_write.

 

Alguem tem mais alguma ideia para contribuir, assim que vou avançando postarei algumas soluções neste post ;)

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

SOLUÇÃO 1

 

Estava pensando em uma solução para esse determinado problema, atualmente não tenho absoluta certeza se o arquivo php junto ao socket se comportam como se fosse um SINGLETON (o que pode ser um problema para esta solução) mas a solução pensada foi:

 

Quando inserirmos no banco de dados, automaticamente nos iremos puxar as conversas que estão como visualizadas = false, isso vai fazer com que se retorne a mensagem que o proprio usuario enviou (e que apareça no chat) e tambem poderá puxar as mensagens que outras pessoas enviaram. Puxaremos tambem no banco de dados as mensagens que estão como marcadas como Local = chat1, isso vai fazer com que se retorne somente as mensagens daquela pessoa.

 

Ate ai tudo bem, e parece ser uma otima ideia, mas como todos nos estamos na mesma porta, acredito que ainda continuaremos a receber as mensagens advindas do chat2. Então como proceder?

 

Se lembra que no arquivo aplicacao.js as mensagens são recebidas desta forma: var mensagem = event.data;

 

Neste caso será que nao poderiamos fazer com que o socket_Write nos retorne 2 parametros como a mensagem e o local (chat1), isso faria com que no javascript ele fizesse uma checagem e filtrasse as mensagens e pegasse somente aquela referente ao chat1? Bem tenho algumas considerações a fazer:

 

  • Problema na segurança, alguem pode ir lá no codigo e tirar essa filtragem e começar a receber a mensagem de todos.
  • Considerando que temos 1000 chats ativos simultaneamente, uma pessoa irá receber todas as mensagens que não são referentes a ela. (E não acho que esses chats privados funcionam desta forma)

 

Atualização: Este metodo não é muito confiavel e dependendo da velocidade de conexão do usuario isso pode se tornar um grande problema.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Solução 2

 

Fazendo uma breve busca na documentação do php foi encontrado um comando que acredito que possa substituir o socket_write, o socket_sendTo, de acordo com o que foi visto parece que ele envia uma resposta para o socket conectado, se estiver conectado ou não, abaixo se encontra um simples exemplo:


<?php
    $sh = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
    if (socket_bind($sh, '127.0.0.1', 4242)) {
        echo "Socket bound correctly";
    }
    $buf = 'Test Message';
    $len = strlen($buf);
    if (socket_sendto($sh, $buf, $len, 0x100, '192.168.0.2', 4242) !== FALSE) {
        echo "Message sent correctly";
    }
    socket_close($sh);
?>

Parece que este comando ele envia a resposta para o socket conectado naquela porta, mais especificamente para um determinado IP que esta conectado, isso evita que diferente da primeira solução, agora as respostas são enviadas para determinados ips conectados na rede.

 

Com isso nos iremos pegar a resposta do usuario, registrar no banco de dados, e criar um loop deste comando socket_sendTo e enviando o ip do pessoal que esta no chat1, acredito que isso evitaria o chat2 receber mensagens paralelas.

 

Esta solução ainda não foi testada, caso funciona estarei voltando aqui para trazer os resultados ;)

 

Atualização: Este metodo não funcionou, como o esperado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Solução 3 - Definitiva

 

 

Analisando mais um pouco o segundo chat (mediumChat) localizado naquele link do github, e analisando tambem alguns chats na internet foi analisado que toda nova conexão de um socket é armazenado dentro de um array.

 

Isso significa que quando voce entra em uma sala de chat global, uma instancia do seu socket é criada, e enumerada como:

Resource id #3
Resource id #4
Resource id #5
.......

Utilizando o comando socket_getpeername é possivel selecionar o ip do socket da pessoa junto a uma porta de acesso (esta porta de acessa nao é a mesma porta de escuta do servidor do socket) diferente para cada usuario que entra (e muda constantemente -> se eu entrar na sala a porta é uma, se eu sair e entrar novamente a porta será outra).

 

Sabendo disso, tudo que devemos fazer é criar um array como por exemplo:

$socketsLista = array();

E quando um novo socket entrar nós iremos adicionar a instancia do socket dentro desse array, no meu caso eu fiz da seguinte forma (ESTE É UM EXEMPLO DO EASYCHAT)

 if($sock === $m_sock){
......
socket_write($msgsock, $headers);
echo "handshak done...\n";

//Insira a variavel $m_sock  dentro do array

$socketLista[] = $_sock;

}

A variavel $m_sock é a responsável por criar uma nova conexão com o socket sempre quando que um novo usuario entra no chat o codigo responsavel por isso pode se encontrar abaixo:

$m_sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

Para realizar um simples teste inicial, nos iremos substituir este comando:

}else{
$bytes = socket_recv($sock, $data, 2048, null);
$d = unmask($data);
foreach ($cls as $socket) {
if($socket != $m_sock && $val > 0){
try{
socket_write($socket,(encode($d)));
}catch(Exception $e){
unset($cls[$socket]);
socket_close($cls[$socket]);
}
}
}
}
} 

Por este:

}else{
$bytes = socket_recv($sock, $data, 2048, null);
$d = unmask($data);
try{
socket_write($socketLista[0],(encode($d)));
}catch(Exception $e){
unset($cls[$socket]);
socket_close($cls[$socket]);
}
}

} 

Isso vai fazer com que todas as respostas sejam enviadas somente para a instancia do socket que esta no index 0 do nosso array (que no caso seria o nosso primeiro usuario que abriu o chat), agora vamos aos testes:

 

  • Abra no navegador o arquivo server.php.
  • Em seguida abra o index.php em uma aba.
  • Agora abra mais 2 novas tabs no seu navegador e abra o index.php em cada uma delas.

 

Agora experimente digitar algum texto dentro dessas duas novas abas que voce abriu, voce verá que nem a 2º aba nem a 3º aba receberam as mensagens enviadas, mas ambas enviaram para o socket, por fim abra a primeira aba (aquela que contem o chat) e veja que voce recebeu 2 mensagens (tais mensagens enviadas das 2º e 3º aba), é claro que se enviarmos uma mensagem pela 1º aba nada ocorre (porque não configuramos isso).

 

Mas a ideia é essa mesmo, agora basta criarmos um banco de dados que armazene qual index do socket está se comunicando com qual index do socket e no socket write colocarmos algo como:

socket_write($socketLista[0],(encode($d)));

socket_write($socketLista[1],(encode($d)));

Que no caso ja estabelecemos uma conexão privada entre o chat 1 e o chat 2, no caso, se colocarmos assim, o chat 3 nao irá enviar nem receber nada, somente o chat 1 e 2.

 

Assim que eu terminar de fazer um teste final (chat privado de uma forma mais automatizada e com banco de dados), estarei postando no github e aqui tambem o projeto final e open source :D

 

Resolvido

Compartilhar este post


Link para o post
Compartilhar em outros sites

  • Conteúdo Similar

    • Por violin101
      Caros amigos, saudações.
       
      Por favor, poderiam me ajudar.

      Estou com a seguinte dúvida:
      --> como faço para para implementar o input código do produto, para quando o usuário digitar o ID o sistema espera de 1s a 2s, sem ter que pressionar a tecla ENTER.

      exemplo:
      código   ----   descrição
           1       -----   produto_A
       
      Grato,
       
      Cesar
    • Por violin101
      Caros amigos, saudações.
       
      Humildemente peço desculpa por postar uma dúvida que tenho.

      Preciso salvar no MySql, os seguinte Registro:

      1 - Principal
      ====> minha dúvida começa aqui
      ==========> como faço para o Sistema Contar Automaticamente o que estiver despois do 1.____?
      1.01 - Matriz
      1.01.0001 - Estoque
      1.01.0002 - Oficina
      etc

      2 - Secundário
      2.01 - Loja_1
      2.01.0001 - Caixa
      2.01.0002 - Recepção
      etc
       
      Resumindo seria como se fosse um Cadastro de PLANO de CONTAS CONTÁBEIL.

      Grato,


      Cesar









       
    • Por violin101
      Caros amigos, saudações.

      Por favor, me perdoa em recorrer a orientação dos amigos.

      Preciso fazer um Relatório onde o usuário pode Gerar uma Lista com prazo para vencimento de: 15 / 20/ 30 dias da data atual.

      Tem como montar uma SQL para o sistema fazer uma busca no MySql por período ou dias próximo ao vencimento ?

      Tentei fazer assim, mas o SQL me traz tudo:
      $query = "SELECT faturamento.*, DATE_ADD(faturamento.dataVencimento, INTERVAL 30 DAY), fornecedor.* FROM faturamento INNER JOIN fornecedor ON fornecedor.idfornecedor = faturamento.id_fornecedor WHERE faturamento.statusFatur = 1 ORDER BY faturamento.idFaturamento $ordenar ";  
      Grato,
       
      Cesar
       
       
       
       
    • Por violin101
      Caros amigos, saudações
       
      Por favor, me perdoa em recorrer a orientação dos amigos, tenho uma dúvida.
       
      Gostaria de uma rotina onde o Sistema possa acusar para o usuário antes dos 30 dias, grifar na Tabela o aviso de vencimento próximo, por exemplo:
       
      Data Atual: 15/11/2024
                                           Vencimento
      Fornecedor.....................Data.....................Valor
      Fornecedor_1...........01/12/2024..........R$ 120,00 <== grifar a linha de Laranja
      Fornecedor_1...........01/01/2025..........R$ 130,00
      Fornecedor_2...........15/12/2024..........R$ 200,00 <== grifar a linha de Amarelo
      Fornecedor_2...........15/01/2025..........R$ 230,00
      Fornecedor_3...........20/12/2024..........R$ 150,00
       
      Alguém tem alguma dica ou leitura sobre este assunto ?

      Grato,
       
      Cesar
    • Por violin101
      Caros amigos, saudações.

      Por favor, me perdoa em recorrer a ajuda dos amigos, mas preciso entender uma processo que não estou conseguindo sucesso.

      Como mencionado no Título estou escrevendo um Sistema Web para Gerenciamento de Empresa.
       
      Minha dúvida, que preciso muito entender:
      - preciso agora escrever a Rotina para Emissão de NFe e essa parte não estou conseguindo.
       
      tenho assistido alguns vídeos e leituras, mas não estou conseguindo sucesso, já fiz toda as importações das LIB da NFePhp conforme orientação.

      Preciso de ajuda.

      Algum dos amigos tem conhecimento de algum passo-a-passo explicando a criação dessa rotina ?

      tenho visto alguns vídeos com LARAVEL, mas quando tento utilizar e converter para PHP+Codeiginter, dá uma fila de erros que não entendo, mesmo informando as lib necessárias.

      Alguns do amigo tem algum vídeo, leitura explicando essa parte ?

      Grato,

      Cesar.
×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.