Java Socket cliente- servidor

Boa tarde, estou com um projeto em Java que utiliza socket. A comunicação dele ja esta praticamente pronta, mas analisando o codigo me deparei com uma duvida. O meu servidor possui um loop que enquanto tiver vivo vai ler e processar o protocolo que eu criei, na parte do cliente eu nao possuo nenhum loop, mas sim metodos que enviam o protocolo para o servidor e espera a resposta dele.
Ilustrando eu tenho a seguinte estrutura:
Na parte do Servidor:

private void processar() {
    do {
        try {
            processarProtocolo(input.readInt());
        } catch (IOException ex) {
            isAlive = false;
            ex.printStackTrace();
        }
    } while (isAlive && liberado);
}

Então o cliente envia uma mensagem:

public void enviarOk() {
    sendData(() -> {
        dos.writeInt(0);
    });
 }

E o servidor lê o codigo “0” e faz algo, podendo retornar alguma informação ou valor, nesse caso depois do “sendData(() -> { dos.writeInt(0);});” eu coloco um input.read().
Minha duvida é a seguinte, essa é a forma correta de realizar a comunicação cliente/servidor? o servidor sempre com um loop processando e o cliente apenas envia o protocolo e no mesmo metodo aguarda a informação. Eu pensei em criar um loop no servidor e outro loop no cliente, entao nesse caso o cliente envia uma solicitação para o servidor mas nao aguarda o retorno, e o servidor envia uma informação para o cliente e atraves do loop ele processa os dados, porem no caso de uma tabela, por exemplo, o cliente vai solicitar as informações para completar a tabela e vai continuar a executar sem aguardar, o servidor vai processar o pedido e enviar as informações, e atraves do protocolo o cliente vai saber que se trata de dados para completar uma tabela, porem qual tabela? como o programa é grande e tem varias tabelas e telas diferentes, como fazer para enviar os dados para a tela certa?

Qual dos dois é melhor, o loop só no servidor ou um loop no servidor e outro no cliente?
Tambem pensei em uma conexão UDP em paralelo e usar multicast para enviar mensagens do servidor para o cliente ou clientes.

Só para complementar, eu tenho varios produtos em uma tabela e com dois cliques abre uma tela para alterar as informações, usando um loop só no servidor eu consigo completar a tabela, ver os dados e alterar sem problema, mas caso um outro usuario entrar no mesmo produto e alterar uma informação o primeiro nao vai ver a alteração, e no caso de dois loops o servidor poderia mandar uma mensagem com os dados novos e ele decidir atualizar ou nao na interface. Mas não sei qual a melhor pratica nesse caso, e queria seguir o caminho certo para nao precisa alterar o projeto todo do programa mais para a frente.
Agradeço a ajuda.

1 curtida

Depende do que você quer fazer. Esta é a forma mais comum de utilização, pois você pode adicionar vários clientes e retornar elementos distintos, tratados ou não por threads separadas.

Isso também pode ser feito, só depende de como você quer manter essas conexões ativas, pois, lembre-se, todo loop tende a repetir os mesmos passos que estão dentro dele.

Você pode criar diversas estruturas de validação e de organização para situações como essa, por exemplo, identificar via token a requisição de dados para preencher a tabela “XPTO” e salvar essa informação em um mapa, por exemplo. Quando o protocolo é retornado com os dados da requisição para a tabela XPTO, você simplesmente valida qual a tabela e lá insere os dados.
Lógico que essa abordagem não é a mais adequada, mas é uma possibildiade. Até porquê, desta maneira, você resolve o problema de qual chamada foi para qual tabela, mas não qual a sequência de chamadas para uma tabela específica (talvez implementar uma fila para processamento de dados enfileirados, precisa pensar).

Entenda que, quanto mais complexa for a solução buscada por ti, mais cimplexa a coisa fica?

Se você estivesse desenvolvendo um sistema web, iria te sugerir o uso de websockets, sem pestanejar.

1 curtida

Entendi, entao no caso qualquer um dos dois esta certo?
O que eu estava pensando em fazer é deixar essa conexão somente para a requisição para o servidor e criar uma outra conexão só para as mensagens do servidor, no caso um datagramsocket ou algo do tipo.
Algo para situações como alguem entra para editar e ja tem outro cliente editando, entao o servidor manda uma mensagem avisando, ai no caso eu criaria uma thread no cliente só recebendo as mensagens e exibindo.

@ghpm99 a comunicação pode ser orientada a conexão (TCP) ou não orientada a conexão (UDP).

Quando falamos de TCP, criamos um servidor que escuta em uma porta específica por conexões de clientes.
O servidor deve rodar como uma thread específica, a qual fica “travada” no método accept do ServerSocket, aguardando as conexões dos clientes. Para cada nova conexão o ServerSocket retornar uma instância de Socket que contém a conexão direta entre o cliente e o servidor. Este socket, por sua vez deve ser tratado por outra thread, que cuidará do recebimentos de pacotes através de um InputStream.
Desta forma sua aplicação pode aceitar diversas solicitações ao mesmo tempo de diversos clientes.

Em relação ao cliente, acho correto trabalhar com thread também, a qual também cuidará do recebimento de pacotes através de um InputStream. Você só deve pensar que sua solicitação ficará independente da resposta.

Agora se optar por estabelecer a conexão via Datagram, depende de sua regra negócio se precisa tratar timeout, reenvio, etc. A implementação é bem diferente, onde cria-se um datagram e o envia, sem a garantira de existir um servidor ou um cliente escutando.
Por sua vez a comunicação multicast depende muito da sua regra de negócio.


Em relação a sua implementação, com base na descrição de existirem vários produtos e um cliente ver a alteração do outro, acredito que a melhor forma seria a implementação TCP.
Sim, cria-se uma thread para o server aceitar conexões dos clientes e para cada nova conexão o servidor instancia uma nova thread para tratar o recebimento de dados.
No lado do cliente, a mesma forma, cria-se uma thread para tratar o recebimento de dados do servidor.

1 curtida

Entendi, meu programa funciona assim:
Servidor inicia e cria uma Thread para ficar dando accept no ServerSocket, assim que aceita ele cria uma outra thread com parametro o Socket que ele gerou, nessa nova Thread eu tenho um loop que enquanto estiver vivo fica ouvindo o input e processando as mensagem.

Minha duvida é justamente em “Em relação ao cliente, acho correto trabalhar com thread também, a qual também cuidará do recebimento de pacotes através de um InputStream. Você só deve pensar que sua solicitação ficará independente da resposta.”, por exemplo eu citei a questao de tabelas, porque meu programa tem um banco de dados que o servidor gerencia, entao o cliente solicita informações para completar a tabela e o servidor consulta o banco de dados e retorna as informações, o cliente recebe as informações e completa a tabela, nesse caso eu preciso que o metodo retorne as informações. Porem eu tenho campos tipo o titulo do programa que completa com o “nome de usuario + data + nome do programa” e o nome do usuario nao é um campo que necessariamente preciso esperar.
É nessa parte minha duvida, imagine assim no caso da tabela com o metodo esperando retorno:
Solicita tabela -> servidor processa e retorna dados -> completa tabela
como ficaria no caso de uma Thread no cliente?
Solicita tabela -> servidor processa
Servidor retorna dados para o cliente -> completa a tabela( mas qual?)

O que eu falei da conexão UDP foi o seguinte, eu usar uma porta para conexão TCP com a seguinte estrutura:
Servidor com Thread e cliente sem Thread
E entao em outra porta eu criaria uma conexão UDP para o cliente ficar recebendo somente mensagens do servidor, em casos como:
O usuario está logado e entao eu altero o nome do usuario dele, o servidor usaria a Conexão UDP para mandar um aviso que o nome do usuario mudou e qual o nome novo.
O usuario esta alterando um produto e outro usuario entra ou altera uma informação no mesmo produto, entao o servidor envia um aviso para ele avisando que um campo foi alterado.

Sei que está meio grande a resposta, mas é que assim, meu programa é um controle de notas, entao eu tenho varias e varias tabelas, entao o setor de compras entra no programa e lança uma ordem de compra, quando a nota chega o almoxarife entra na ordem de compra e lança uma nota, e eu uso a mesma estrutura de tabela(colunas) para varias telas, por exemplo uma tela lista todas as notas, a outra lista somente as notas em aberto, e eu deixo o servidor filtrar isso já que o programa suporta varios bancos de dados diferentes. Sempre que penso em colocar uma Thread no cliente eu esbarro na seguinte pergunta, imagina que eu cliquei para ver todas as notas, entao o cliente mandou uma solicitação para o servidor pedindo as informações da tabela, o retorno do servidor tem delay, se o cliente clicar para listar todas ordem de compra sem esperar o retorno do servidor, chegaria duas mensagens: uma com a lista das notas e outra com a lista da ordem de compra, como eu deveria fazer para ele saber que tem que ignorar a de notas? Já que a tabela visivel é somente a de ordem de compra, e se eu tentar completar a de notas vai dar null point, já que cada tela é criada na hora e assim que fecha é destruída.

Por isso eu adotei a forma de: o usuario clicou em notas, o cliente solicita informações para o servidor e aguarda o retorno, assim que o servidor retorna o metodo pega as informações e retorna para a tabela. A solicitação do cliente é feita em uma Thread, mas o programa fica em uma tela de loading enquanto as informações nao retorna do servidor.

Devo continuar seguindo essa forma ou adotar um loop no servidor e outro no cliente?