Estou com o seguinte problema, preciso passar uma string de resposta a requisição do cliente mas não estou sabendo como enviar e receber a resposta, consigo enviar a requisição através do cliente passando como string e consigo receber no server, mas as repostas não.
Estou tentando enviar a resposta ao cliente no server assim:
buffer.clear();
buffer.put(resposta.getBytes());
buffer.flip();
while (buffer.hasRemaining()) conexao.write(buffer);
Por favor, siga essas dicas ao postar códigos no fórum:
Seu problema me parece ser o clássico caso onde você acha que um único write vai representar um único read do lado do cliente. Bem, não é assim que funciona.
Cada read do socket irá ler o dado que estiver disponível do canal. Como sua String ainda pode estar sendo transmitida, você deverá testar se a quantidade de bytes esperado já foi lida.
Para isso, seria bom enviar, antes do texto em si, a quantidade de caracteres que a String tem. Dê uma lida nesse tópico:
Tenho necessidade de montar um servidor com alta disponibilidade, mas da forma mais simples possivel, meu conhecimento de java, protocolos é muito restrito, qualquer coisa que saia da estrutura que montei, já fico “boiando”, tinha montado app servidores usando threads, mas dava deadlocks, travava entre outros problemas, passei essa semana toda, estudando, sendo ajudado por colegas, comprando livros e cheguei num app servidor usando selector, channel, bytearray sem threads explicitas e enviando e recebendo strings do servidor, só encontrei exemplos na web usando inteiros.
A string “enviar” não vai de uma vez só para o servidor? Tem alguma coisa que precise ser feita a mais para garantir a troca de informações entre os dois? Não é seguro colocar em produção, dessa maneira? Quando falo de segurança aqui, estou me referindo a troca de informações.
Nesse caso, você vai ter que continuar estudando… Afinal “alta disponibilidade” por si só envolve um software complexo.
Mesmo que feito da forma “mais simples possível”.
Se você achava que ia ser só sair chamando metodozinhos prontos da API, pode tirar o cavalinho da chuva.
Toda aplicação de redes tem um protocolo. Sem exceção.
Ele nada mais é do que o conjunto de regras que você usa para fazer a comunicação.
Da forma que você está fazendo, o protocolo também existe, mas é ruim, e não prevê corretamente o que ocorre quando se transmite via TCP/IP.
Você deve parar um tempo e estruturar seu protocolo. É o básico, sem isso, não dá para começar.
Se você não quer parar para aprender, uma alternativa seria não usar um protocolo próprio, e tentar usar algo já existente, como o projeto RedDwarf.
Talvez sim, mas talvez não. Não existem garantias.
A única coisa garantida é que os dados chegam, na mesma ordem que saíram e com a mesma informação que saíram.
Mas é você que tem que criar meios de saber se a String chegou inteira, ainda precisa esperar por mais um pedaço dela.
Sim. Estruturar corretamente seu protocolo.
De jeito nenhum. Um código assim está condenado a falhar.
Quanto ao seu código, sem identação ou colorização, não vou nem me dar ao trabalho de ler.
Por favor, use a tag code como já indiquei.
Boa noite Vini, mais uma vez obrigado.
Como lhe disse, estou aprendendo, mas vou te confessar é muito dificil sem ajuda, comprei o Livro Java em Rede Recursos Avançados de Programação, autor Daniel Costa, pois foi o unico que achei e ainda assim, só te dá os primeiros passos superficialmente, não é uma biblia. A web é um mar de informações, mas pra quem tá precisando se aventurar nisso, gera uma confusão total, um colega me deu a idéia de procurar por Java nios e foi o que me deu um melhor resultado e direcionamento. Duas coisas eu já tenho como base, o primeiro campo até então é o que deve ser feito e o segundo de quem, agora preciso por o tamanho no primeiro campo, onde será a primeiro pedaço da mensagem a chegar e ficar conferindo no servidor se ela chegou inteira para só então processa-la. Desta maneira seria um protocolo confiavel?
Eu geralmente coloco o tamanho da mensagem entre as primeiras informações no pacote dos meus protocolos. Assim fica fácil esperar a mensagem corretamente, seja no servidor ou no cliente.
Como você está usando o NIO, é bem fácil fazer isso, pois basta enviar os remaining bytes.
Outra coisa, por que você está codificando sua mensagem inteira como String?
"02|"+id+"|"+lat+"|"+lon+"|"+vel
Já que você está montando um protocolo, por que não coloca esses dados dentro do ByteBuffer em sua forma binária mesmo?
Basta usar os métodos “put” do ByteBuffer.
int i = 0;
int tamanho = 0;
while(cliente.read(buffer) != -1){
buffer.flip();
if (i == 0) tamanho = buffer.getInt();
i++;
receber += charset.decode(buffer);
buffer.clear();
}
e ai vou recebendo o restante da mensagem e depois comparo se o tamanho é igual e executo a operação, caso contrario ignoro, é isso?
Se você já fez um getInt com o tamanho, pode depois colocar a leitura dos dados num while. Afinal, agora você já sabe exatamente quantos bytes esperar.
Maravilha Vini, vou estudar a criação de protocolos.
Depois disso, você acha que vou estar com um sistema confiável, para colocar em produção?
Transferindo bytes direto, ainda tenho que implementar segurança, criptografia?
Qual seria o proximo passo? Ouvi falar em 3way handshake (SYN/ACK), ssl, implementar singleton para acesso ao banco, testes de estresse, pool de threads, numero maximo de threads, entre outras, um mundo de coisas.
Mas de antemão muito obrigado mesmo pelo interesse em ajudar.
Se seu protocolo for para uso interno, só LAN da sua empresa, isso não é necessário.
Se for implementar segurança, para deixar seu servidor na internet, considere usar algum protocolo já estabelecido, como SSL (as classes SSLSocket e SSLServerSocket são para isso).
Three-way handshake é a forma que o TCP/IP faz a conexão. Só de abrir um socket significa que isso já foi feito.
Uma coisa que você vai ter que implementar são mensagens de Keep Alive / Alive, para saber se um cliente desconectou.
Não é uma boa ideia contar com a exception de SocketClosed, pois ela pode levar muitíssimo tempo para chegar (o timeout do socket costuma a ser de vários minutos).
Outro detalhe que incomoda um pouco é desligar o algorítmo de Nagle (com o comando socket.setTcpNoDelay).
Isso é importante se suas mensagens forem pequenas (num protocolo binário, muitas delas serão).
Se você quer alta disponibilidade e alto volume, estude a parte de Selectors do java.nio, pois ele permite que o servidor gerencie um número grande de clientes com uma pequena quantidade de threads.
Singleton para banco de dados é uma idiotice, repetida por mais vezes do que eu gostaria de ver aqui no GUJ. Especialmente aqueles que mantém uma conexão aberta durante toda sua aplicação. Entretanto, essa já é outra discussão. Primeiro, aprenda a transmitir daos pela rede direito. Há muita coisa pela frente ainda. Depois falamos de opções para banco de dados robustas, com pool de conexões e injeção de dependências.
Tenho um sistema rodando a 11 meses, no Android e Tomcat com Windows server 2008/SqlServer2008, fazendo requisições http via paginas jsp.
Funcionando perfeitamente, só que o consumo está muito alto, cada aparelho faz em media 5 requisições automaticas sem intervenção do usuario.
Um colega daqui mesmo, recomendou migrar pra sockets.
O sistema consiste em enviar sua localização a cada 1 minuto, receber Mensagens da central, receber sua area e posição e fora outras consultas disparadas pelo proprio usuario.
Já estou utilizando Selectors, por isso te disse que o servidor está perfeito, consumo baixo, sem deadlocks, sem threads massivas, atendendo varias requisições sem travar em momento algum.
Agora acho que estou fazendo besteira, cada vez que conecto, envio a informação e desconecto do servidor. É correto ficar conectado o tempo todo e se houver uma falha mandar conectar novamente?
Tenho um timer na tela principal que fica mostrando ao usuario seu ultimo acesso ao servidor e disparo um alarme se ele ficar mais de 2 minutos sem enviar nada.
Existem três modelos:
a) Modelos com estado: O cliente conecta e se mantém conectado. Nesse caso, você precisa desses controles de Keep Alive que comentei. A desvantagem é que o cliente, enquanto conectado, está consumindo recursos do servidor - o que pode ser caro se sua informação de estado for pequena;
b) Modelos sem estado: O cliente conecta e desconecta. É o que protocolos como o HTTP usam. O servidor não precisa controlar a conexão, o que simplifica sua implementação. Porém, se você tem que restaurar estado entre os clientes, isso pode ficar caro;
c) Modelos sem conexão: Com UDP, você pode fazer comunicação sem haver qualquer tipo de conexão. O protocolo é orientado a datagramas. É o mais leve que você poderia chegar. A desvantagem é que o UDP não garante que os pacotes cheguem ao destino e nem a ordem que isso acontece. O UDP é muito usado em streaming, quando há redundância de informação ou necessidade de transmissão em tempo real. Por exemplo, se você enviasse a localização a cada 10 segundos, talvez não houvesse problemas em perder um pacote do meio do caminho, já que dali a 10 segundos teria outro (também não adiantaria retransmitir e esperar o pacote 1, se o pacote 2 chegar na rede antes, com uma informação mais atualizada - o TCP fará isso, o UDP te entregará o 2 primeiro e quando o 1 chegar, vc pode descarta-lo).
Agora, não dá para falar em “leve ou pesado”, sem falar também em identificar o gargalo. Você já rodou algum profiler na sua aplicação? O gargalo da rede pode estar em vários locais:
a) Pode ser em algum processamento pesado do lado do servidor (e nesse caso, seria importante identificar em que ponto do processamento isso ocorre);
b) Pode ser lag da rede em si;
c) Pode ser gargalo no dispositivo móvel.
e) O gargalo pode ser no banco.
Quando você fala em “o consumo está muito alto”, você está falando do consumo de que? Memória? Processamento? Banco?
Como ele disse “Android” deve ser consumo de banda.
Se o ZeroMQ não fosse meio chato para fazer deploy (já que exige a instalação de um arquivo de código executável binário a ser chamado via JNI) eu até diria para ele usar o ZeroMQ no Android.
O ZeroMQ já abstrai vários desses detalhes de retransmissão, protocolo etc. Você se limitaria a codificar corretamente sua aplicação no cliente e no servidor.
Acho que fico na opção b modelos sem estado, não preciso verificar os smartphones conectados, isso eu deixo a cargo do motorista, ele é quem deve se preocupar com a perda de sinal de dados do seu aparelho, a rotina mais pesada é realmente o insert das localizações, pq todos sem exceção tem que fazer para que o sistema identifique sua localização e enquadre ele dentro de uma cerca eletronica onde ele poderá receber um chamado, e como cada chamado significa dinheiro todos querem receber imediatamente, mas para isso precisam estar identificados através de sua localização, com mais de dois minutos sem enviar sua localização ele perde a vez, eu não preciso dizer como eles ficam felizes quando isso acontece. Cada empresa nossa cliente tem em media 200 carros que a cada turno trabalham entre 100 e 150, multiplicando isso em requisições, dá pra perceber que a coisa fica feia. Por isso estou tão preocupado com a alta disponibilidade do servidor, já fiz alguns testes de estresse e usando o nios a coisa tá fluindo bem, o que me anima a “encher o saco” de vocês, com tantas perguntas, mas pra quem a 1 semana atrás não sabia nem por onde começar e com ajuda de vocês a coisa tá indo, nunca é na velocidade que precisamos, mas nem com literatura especializada eu consegui, entender todos os conceitos.
O consumo alto está no protocolo http que utilizo hoje, me referindo ao consumo do plano de dados de cada motorista, visto que cada requisição para receber 0 ou 1 consome 1kb, quando utilizando o socket consumiria 1k, ou seja 1023k a menos.
Nunca ouvi falar desse ZeroMQ, mas com certeza vou buscar saber.
Está sendo um grande desafio aprender Java (o conhecimento que possuo é bem basico (faculdade)) e ou uso de Sockets ao mesmo tempo.