Pular para o conteúdo principal

Java e Redes: Implementando um ServerSocket

Introdução

Uma dúvida de um aluno da Academia Java me incentivou a dar continuidade ao assunto de programação Java para redes, iniciado em Java e Redes: Consultando um serviço com Socket que mostrava como consultar um serviço do NIST por meio da API de redes da Plataforma Java, este post apresenta a implementação de um java.net.ServerSocket que responde aos clientes com um determinado arquivo.

Exemplo

Para a criação de um ServerSocket que será responsável por escrever os bytes de um determinado arquivo no canal de comunicação com o cliente, definiremos a porta no construtor, conforme segue:
int port = 8080;
ServerSocket server = new ServerSocket(8080);

Apenas a criação do objeto server da classe ServerSocket não permite ainda a comunicação, para tanto é necessário que o ServerSocket passe a aceitar conexões, e isto é feito pelo método accept, este método é bloqueante, ou seja, faz com que o programa fique parado até que o servidor receba uma requisição, e quando isto ocorrer cria um Socket para comunicação; Socket este que tem sua referência armazenada na variável socket, de acordo com a linha apresentada abaixo:
Socket socket = server.accept();
E então, após uma requisição ser recebida, podemos recuperar o fluxo para escrita no socket, por meio do método getOutputStream e montar o fluxo de escrita otimizado com uso de um objeto do tipo BufferedOutputStream , conforme trecho de código abaixo:
OutputStream socketOutput = socket.getOutputStream();
BufferedOutputStream output = new BufferedOutputStream(socketOutput);
Para ler o arquivo determinado criaremos um fluxo de leitura otimizado, conforme segue:
String pathname = "feed.png";
FileInputStream fileInput = new FileInputStream(pathname);
BufferedInputStream input = new BufferedInputStream(fileInput);
Depois de montado o fluxo de entrada (input), que lê um determinado arquivo, e o fluxo de saída (output), basta realizar a leitura da entrada e escrever na saída, enquanto existirem bytes a serem lidos, conforme trecho abaixo:
int data = 0;
while( (data = input.read()) !=-1){
 output.write(data);
}
O método accept está em um laço infinito while(true){} e a forma de interromper a execução do servidor é interromper o processo no console ou na sua IDE preferida, ou ainda determinar a quantidade de vezes que o servidor vai executar o laço.

ServerFileSocket.java

Segue o código completo da classe que implementa o servidor que responde aos clientes com o arquivo determinado.
package br.eti.castro.blog.samples.networking;
// imports ocultos
public class ServerFileSocket {
 //o tratamento de excessoes foi simplificado (throws UnknownHostException, IOException)
 //para simplificar o entendimento do exemplo
 public static void main(String[] args) throws IOException {
  //declarando de objetos para a leitura do arquivo
  String pathname = "feed.png";//pode conter o caminho
  BufferedInputStream input = null;
  FileInputStream fileInput = null;
  
  //declarando de objetos para a escrita no fluxo do socket
  OutputStream socketOutput = null;
  BufferedOutputStream output = null;
  //Criando um servidor que atendera na porta 8080
  int port = 8080;
  ServerSocket server = new ServerSocket(port);
  while(true){
   //O metodo accept faz com que o servidor aguarde uma requisicao
   //Quando isto ocorrer cria um Socket para comunicacao
   Socket socket = server.accept();
   //montando o fluxo de leitura do arquivo otimizado
   fileInput = new FileInputStream(pathname);
   input = new BufferedInputStream(fileInput);
   
   //montando o fluxo de dados para escrita no socket
   socketOutput = socket.getOutputStream();
   output = new BufferedOutputStream(socketOutput);
   int data = 0;
   //lendo o arquivo
   while( (data = input.read()) !=-1){
    //escrevendo o dado lido no socket
    output.write(data);
   }
   //fechando o fluxo de entrada
   input.close();
   //fechando o fluxo de saida
   output.flush();
   output.close();
   //fechando o socket
   socket.close();
   
  }
 }
}
ClientFileSocket.java

Esta classe não está explicada detalhadamente no artigo, porém acredito que o artigo anterior: Java e Redes: Consultando um serviço com Socket, juntamente com este podem esclarecer sobre o funcionamento da classe.

package br.eti.castro.blog.samples.networking;
//imports ocultos
public class ClientFileSocket {
 //o tratamento de excessoes foi simplificado (throws UnknownHostException, IOException)
 //para simplificar o entendimento do exemplo
 public static void main(String[] args) throws UnknownHostException, IOException {
  //declarando de objetos para a leitura do fluxo do socket
  BufferedInputStream input = null;
  InputStream socketInput = null;
  //declarando de objetos para a escrita do arquivo
  String pathname = "novo.png";
  FileOutputStream fileOutput = null;
  BufferedOutputStream output = null;
  //criando o socket para o localhost na porta 8080
  String host = "localhost";
  int port = 8080;
  Socket socket = new Socket(host, port);
  //recuperando o fluxo de dados
  socketInput = socket.getInputStream();
  //montando o fluxo de leitura do socket otimizado 
  input = new BufferedInputStream(socketInput);
  //montando o fluxo de escrita do arquivo otimizado 
  fileOutput = new FileOutputStream(pathname);
  output = new BufferedOutputStream(fileOutput);
  //lendo o socket
  int i = 0;
  while( (i = input.read()) !=-1){
   //escrevendo o arquivo
   output.write(i);
  }
  //fechando o fluxo de entrada
  input.close();
  //fechando o fluxo de saida
  output.flush();
  output.close();
  
  //fechando o socket
  socket.close();
 }
}
O exemplo está preparado para rodar ambas as classes na mesma máquina, pois a classe ClientFileSocket está configurada para procurar o ServerSocket na mesma máquina (host = "localhost"), porém é interessante rodar cada uma das classes em uma máquina diferente, bastando para tanto alterar o valor da variável host.

Outro ponto importante, é com relação a porta utilizada, caso a porta 8080 já esteja sendo utilizada, basta alterar a variável port, que deve ter sempre o mesmo valor na classe ServerFileSocket e na classe ClientFileSocket.
Além disso é possível alterar o arquivo enviado, alterando o valor da variável pathname na classe ServerFileSocket e também o nome em que a classe ClientFileSocket salva o arquivo alterando variável de mesmo nome.

Teste se possível em máquinas diferentes, alterando as variáveis indicadas, tente ainda alterar o arquivo enviado.

Até mais!
Marcelo de Castro
http://twitter.com/mcastroinfo
http://www.globalcode.com.br/instrutores/MarceloCastro
Outros posts: http://blog.globalcode.com.br/search/label/MarceloCastro

Comentários

Postagens mais visitadas deste blog

Saiba como programar para Arduino sem ter nenhum hardware disponível

O Arduino já é uma tecnologia muito difundida entre os amantes de tecnologia. É difícil encontrar um profissional da computação que não brincou um pouco com esta ferramenta de prototipagem ou, que gostaria de fazer isso. Porém, em alguns casos, o programador quer conhecer o arduino mas não dispõe de nenhum hardware, nem mesmo da placa. Como isso poderia ser resolvido? A primeira resposta seria aquela mais simples e direta: ir as compras. Isso pode ser feito em uma loja física ou pela internet. No meu caso, por exemplo, tive a felicidade de encontrar em um site (não me lembro qual) um kit arduino, com um conjunto de sensores e um DVD com 41 vídeo aulas. Mas digamos que o profissional não esteja passando por um bom momento financeiro, ou ainda, simplesmente não queira comprar o Arduino sem antes conhecê-lo um pouco melhor. Para a última situação também já existe uma resposta, e diga-se de passagem, uma excelente resposta. Trata-se do site 123D Circuits.io . Depois de criar seu u

Entendendo como funciona a programação de computadores: linguagens de programação, lógica, banco de dados

Nesse post, diferente dos últimos que foram mais enfáticos nas experiências com tecnologias, vou focar um pouco mais nos profissionais que estão começando, ou pretendem ingressar na área de desenvolvimento de software, falando sobre conceitos fundamentais relacionados a programação em geral . Mercado de trabalho para programação Conforme já sabemos, o mercado de desenvolvimento de software, especialmente no Brasil, continua em franca expansão, sendo que cada vez mais as empresas buscam desenvolver seus próprios sistemas usando as mais diferentes e novas tecnologias. Algumas matérias interessantes: As seis profissões mais valorizadas em 2010 no IDG Now! Muitas vagas e sensação de reaquecimento da economia Por isso, a área de desenvolvimento de software tem despertado interesse em muitos profissionais de outras áreas que desejam mudar de profissão, já que as oportunidades de trabalho tendem a ser maiores. Esse é um perfil presente em muitos dos clientes da Globalcode que acabou m

JSON fácil em Java com GSon !

Ola pessoal ! O formato JSON ( J ava S cript O bject N otation) vem se consagrando cada vez mais na comunicação de dados, principalmente nos dispositivos móveis devido a esse formato ser mais leve que o XML e também mais legível. Uma prova disso são as inúmeras bibliotecas que existem para manipular esse formato, e no caso do Android, o suporte ao JSON é nativo. Mas apesar de ter esse suporte nativo, algumas operações devem ser feitas manualmente e o código acaba ficando um pouco verboso e repetitivo, já que para cada objeto que se deseja transmitir é necessário fazer um método que lê as propriedades do JSON e faz as devidas atribuições no seu objeto Java. Vamos supor o seguinte objeto sendo transmitido em JSON: {   user: {     id: 123456,     name: "Neto Marin",     username: "netomarin",     email: "netomarin@globalcode.com.br"   } } Se você fosse tratar um Webservice que envia esse JSON para o seu aplicativo Android, além de criar a o