Servidores NIO

Caros, antes de mais nada, gostaria de dizer que é um prazer está participando desse forum.
Estive um tempo afastado da programação, mas o bom filho sempre a casa retorna :slight_smile:

Gostaria da ajuda de vcs para saber o que estou fazendo de errado no código abaixo.
A idéia é bem simples:

  • Queria simplesmente imprimir o conteúdo recebido do cliente na tela do servidor
  • Depois fazer com queo UpperCase do texto
  • E depois enviar de volta pra o cliente tudo em maiúsculo

Por favor, alguém tem alguma idéia o que está acontecendo de errado. O código que estou enviando é de um servidor e de um cliente.
Neste código, a parte demarcada como //////////////////////////////////////////////////// é apenas algumas tentativas que fiz…

=> SERVIDOR

import java.net.;
import java.nio.
;
import java.nio.channels.;
import java.util.
; // Necesario para usar a colecao Set (conjunto) de java.

public class ServidorEcoAlteradoNIO {
public static final int PORTO = 8000; // porto padrao

public static void main(String[] args) throws java.io.IOException {

// Se cria um canal de saida com destino sendo a saida padrao (monitor).
WritableByteChannel canalSalida = Channels.newChannel(System.out);	

// Se cria um canal para o ServerSocket e o configura não-bloqueado.
ServerSocketChannel canalServidor = ServerSocketChannel.open();
canalServidor.configureBlocking(false);

// Se extrai o socket do servidor associado e o liga a um enredeco (nome e porto)
ServerSocket socketServidor = canalServidor.socket();
InetSocketAddress dirSocket = new InetSocketAddress("localhost", PORTO);
socketServidor.bind(dirSocket);

// Se cria um selector
Selector selector = Selector.open();

// O canal é registrado no objeto selector para eventos de conexoes que estao chegando
canalServidor.register(selector, SelectionKey.OP_ACCEPT );
System.out.println( "O servidor esta escutando no porto: "+ PORTO );

while (true) { // loop infinito do servidor

	// select() espera até que 1 ou mais canais registrados tenham lancados eventos de I/O
	selector.select();

	// selectedKeys() devolve um conjunto que contem SelectionKeys. (chaves)
	// Cada SelectionKeys (chave) representa um canal que tem algum evento de I/O e pode ser usado para acessar o canal
	Set claves = selector.selectedKeys();
	
	// Se cria um iterador para percorrer o conjunto.
	Iterator it = claves.iterator();
	
	// percorre o iterador.
	while (it.hasNext()) {

			SelectionKey clave = (SelectionKey) it.next(); // Se obtem cada SelectionKey (chave) do conjunto.
			
			// Se elimina a chave do conjunto. Caso não faca isso a chave continuara no conjunto e 
			// vai parecer que o evento que ela representa voltou a ocorrer
			it.remove();

			
		try {
			
			if (clave.isAcceptable()) {
				// Estamos neste momento em uma conexo que esta chegando: O cliente solicitando uma conexao

				// Cria-se o canal do socket a partir dessa chave selecionada, para lidar com a conexao
				SocketChannel canalCliente = (SocketChannel) canalServidor.accept();
				
				System.out.println("Accepted connection from " + canalCliente);
				
				// Se configura o canal como nao-bloqueado
				canalCliente.configureBlocking(false);
				
				// O canal eh registrado no objeto selector para os eventos de escrita
				canalCliente.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);	
				
				/* Permite anexar o buffer a chave, recuperando-o depois dentro dos IF,s... */
				// Se cria um ByterBuffer e se certifica que ele esta limpo 
				// O canal eh registrado no objeto selector para os eventos de escrita
				SelectionKey clientKey = canalCliente.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
        		ByteBuffer buffer = ByteBuffer.allocate(1024);
        		buffer.clear();
        		clientKey.attach(buffer);	
				
			}

			if (clave.isReadable()) {
				// O servidor esta pronto para ler os dados da requisicao do cliente.

				// Se obtem o canal do socket que esta associado a chave.
				SocketChannel canalCliente = (SocketChannel) clave.channel();
				
				// Se configura o canal como nao-bloqueado
				canalCliente.configureBlocking(false);
				
				/* Permite recuperar o buffer anexado, no momento da aceitação, da chave */
				ByteBuffer buffer = (ByteBuffer) clave.attachment();
				
				// O buffer eh preparado para ler do canal.
				buffer.clear();
				
				
				// O conteudo do buffer eh lido do canal do cliente 
				canalCliente.read(buffer);					

				
				
				////////////////////////////////////////////////////

				// Create a character ByteBuffer
    			CharBuffer cbuf = buffer.asCharBuffer();				
				//cbuf.put("Uma string");
				cbuf.flip();
   				String s = cbuf.toString();
   				System.out.println(s); 	
   				
				String response = s.toUpperCase();
   				byte[] data = response.getBytes("UTF-8");
    			buffer = ByteBuffer.wrap(data);
   				
   				// Queria simplismente imprimir o conteúdo recebido do cliente na tela do servidor
   				// Depois fazer com que o UpperCase do texto
   				// E enviar de volta pra o cliente tudo em maiússculo
   				
   				////////////////////////////////////////////////////
   								

			}
			
			if (clave.isWritable()) {
				// O servidor esta pronto para escrever os dados da requisicao do cliente.

				// Se obtem o canal do socket que esta associado a chave.
				SocketChannel canalCliente = (SocketChannel) clave.channel();
				
				// Se configura o canal como nao-bloqueado
				canalCliente.configureBlocking(false);

				/* Permite recuperar o buffer anexado, no momento da aceitação, da chave */
				ByteBuffer buffer = (ByteBuffer) clave.attachment();

				
				// O buffer eh preparado para escrever no canal.
				buffer.flip();
				
				// O conteudo do buffer eh escrito no canal do cliente 
				canalCliente.write(buffer);
				
				// Invoque este método após escreve dados no buffer.
				buffer.compact();

			}				
			
	    } catch (java.io.IOException ex) {
			clave.cancel();
			clave.channel().close();	
	    }
   }
}

}
}

=> CLIENTE
import java.net.;
import java.io.
;

public class TCPClientTry {
static BufferedReader userIn;

public static void main (String args[]) {

String texto;
Socket s = null;

// int serversocket = 7;
int serversocket = 8000;
try{
// 1o passo
s = new Socket(“localhost”, serversocket);
if(s == null)
System.out.println(“NAO CONSEGUIU CRIAR O SOCKET”);

		System.out.println("Porta do cliente: "+ s.getLocalPort() + "\n");
		
		// 2o passo
		DataInputStream in = new DataInputStream(s.getInputStream());
		DataOutputStream out = new DataOutputStream(s.getOutputStream());
		
		System.out.print("Digite o texto: ");
		texto = "";
		// 3o passo
		while(!texto.equals("fim")){
            texto = "";
            // Buffer input aqui      
			userIn = new BufferedReader(new InputStreamReader(System.in)); 
	        texto = userIn.readLine();

			out.writeUTF(texto); 			
			String data = in.readUTF();	      
			System.out.println("Texto recebido: "+ data) ;      
			
			System.out.print("Digite o texto: ");			
		}
   }
   catch (UnknownHostException e){
   	System.out.println("Sock:"+e.getMessage()); 
   }
   catch (EOFException e){
   	System.out.println("EOF:"+e.getMessage());
   }
   catch (IOException e) {
   	System.out.println("IO:"+e.getMessage());
   }
   finally {
   	if(s!=null) 
   		try {
   			s.close();
   		} 
   		catch (IOException e) {
 	            System.out.println("close:"+e.getMessage());
 	    }
    }

}
}

povo

Gostaria de perguntar mais 2 coisas (a segunda é mais importante :-):

1 - Vcs sabem dizer porque o código dentro do clave.isWritable() desse exemplo que te passei não funciona? Pergunto isso pois o código do link tb é um servidor de echo, só que ao contrário do que vc passou (qua aliás funciona muito bem, obrigado :-), ele foi estruturado do jeito que te passei, a únia diferença é que não faz alteração nos dados para enviar de volta.

http://www.javafaq.nu/java-example-code-605.html

2 - Tentei alterar o código que vc passou para funcionar como se fosse um walk-talk, ou seja em vez de simplesmente ecoar uma mensagem, o servidor pega os dados do teclado e envia para o cliente.
Pô, não sei que “cabeçada” eu tô fazendo, mas quando altero o buffer com o novo dado, o programa não funciona mais…
O cliente envia a mensagem e o servidor recebe. O servidor pede os dados, mas quando eu dou enter pra confirmar o texto digitado não acontece mais nada (parece que fica esperando por alguma coisa… :frowning: Não é problema do cliente, pois pra ele é indeferente…

=> Olha o que tentei fazer:

if (clave.isReadable()) {
… (aqueles passos do código que vc passou)

          /////////////////////
               
                // Declarados no corpo do main
                // ReadableByteChannel canalIn = Channels.newChannel(System.in);
                 // WritableByteChannel canalSalida = Channels.newChannel(System.out);   

                 // Apresenta as informações do cliente na tela do servidor
                 String temp =  "Digite texto: ";
                 byte[] datatemp = temp.getBytes("UTF-8");
                 buffer = ByteBuffer.wrap(datatemp);                    
                 canalSalida.write(buffer);

                 // Le do teclado
                 buffer.clear();
                 int i = canalIn.read(buffer);
                 buffer.flip();

                 // Devia enviar de volta pro cliente...
                 canalCliente.write(buffer);
                 clave.interestOps(SelectionKey.OP_WRITE);


                 /////////////////////

=> Olha o que tentei fazer 2 (apelando agora :slight_smile: Fiz praticamente os mesmo passos que foi feito pra ecoar, mas mesmo assim continua no mesmo

if (clave.isReadable()) {
… (aqueles passos do código que vc passou)

       /////////////////////
                // ReadableByteChannel canalIn = Channels.newChannel(System.in);
                // WritableByteChannel canalSalida = Channels.newChannel(System.out);   

                 // Apresenta as informações do cliente na tela do servidor
                 String temp =  "Digite texto: ";
                 byte[] datatemp = temp.getBytes("UTF-8");
                 buffer = ByteBuffer.wrap(datatemp);                    
                 canalSalida.write(buffer);

                 // Le do teclado
                 buffer.clear();
                 int i = canalIn.read(buffer);
                 buffer.flip();


                 byte[] out = new byte[i];
                 buffer.get(out);
                 String outs = new String(out);                                         
                 byte[] data = outs.getBytes("UTF-8");
                 buffer = ByteBuffer.wrap(data);
                

                 // Devia enviar de volta pro cliente...
                 canalCliente.write(buffer);
                 clave.interestOps(SelectionKey.OP_WRITE);


                 /////////////////////

Povo, se mais alguém tiver idéia, toda ajuda é bem vinda!!!