O que é um socket?
De uma forma muito simples e rápida (visto isto ser matéria que diz respeito a Comunicações por Computador), um socket é uma das pontas de um canal de comunicação entre duas máquinas.
Exercício 1: Servidor de eco
Para implementar o servidor de eco vamos usar a classe java.net.ServerSocket, que serve para receber conexões externas com o método accept. Este método devolve um objecto do tipo java.net.Socket que comunica com o cliente cuja conexão foi aceite com accept.
public class EchoServer {
public void start() throws IOException {
ServerSocket server = new ServerSocket(5000); // Iniciar o servidor
// à escuta na porta 5000
Socket client = server.accept(); // Aceitar uma ligação
while (true) {
serve(client); // Servir este cliente
client = server.accept(); // Aceitar uma ligação nova
}
}
private void serve(Socket client) throws IOException {
// ...
}
}
Para efectuar qualquer tipo de comunicação temos à nossa disposição duas streams: uma para enviar dados (output) e outra para receber dados (input). Como queremos enviar e receber linhas de texto, não vamos utilizar estas streams directamente, porque o seu interface é bastante primitivo (só permite o uso directo de arrays de bytes). Vamos embrulhar estas streams em objectos que disponibilizam métodos que trabalham com strings: BufferedReader e PrintWriter:
private BufferedReader getSocketReader(Socket client) throws IOException {
return new BufferedReader(new InputStreamReader(client.getInputStream()));
}
private PrintWriter getSocketWriter(Socket client) throws IOException {
return new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
}
Com isto, para servir o cliente basta passar linhas da stream de input para a de output:
private void pump(BufferedReader reader, PrintWriter writer) throws IOException {
String line = reader.readLine();
while (line != null) { // Repetir enquanto existirem linhas para ler
writer.println(line);
writer.flush(); // Necessário para forçar envio
line = reader.readLine();
}
}
A chamada a flush() é necessária porque PrintWriter usa um buffer interno para minimizar o número de operações de escrita. Se pedirmos para escrever uma linha pequena o buffer não enche e essa linha só será enviada quando o buffer acumular linhas suficientes para encher. Ao chamar flush(), estamos a forçar a escrita e a linha é enviada imediatamente.
Só falta agora escrever o método serve. Com todas as suas partes preparadas isto é bastante simples:
private void serve(Socket client) throws IOException {
try {
BufferedReader reader = getSocketReader(client);
PrintWriter writer = getSocketWriter(client);
pump(reader, writer);
} finally {
client.close();
}
}
Reparem no uso de try-finally para garantir que a ligação é fechada tanto em caso de sucesso ou de falha.
Testar
Para testar isto podemos usar o seguinte método main:
public static void main(String[] args) {
try {
new EchoServer().start();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Ooops", ex);
}
}
E, conforme sugerido no enunciado, usamos o comando telnet como cliente:
$ telnet localhost 5000
Olá!
Olá!
Yupeee! Tá a funcionar!
Yupeee! Tá a funcionar!
1 commentários:
Obrigado pela massagem inicial!
A ver se consigo chegar ao chat até ao dia do teste.
Enviar um comentário