Buscar

Comunicacao por sockets

Prévia do material em texto

Comunicação por sockets
 
Prof. Marcos Barretto
 
1.Introdução
 
A comunicação entre máquinas é fundamental na integração de sistemas, como em:
Máquinas de comando numérico recebendo programas de sistemas CAD ou enviando o status da produção a
sistemas supervisórios (SCADA –Supervisory Control and Data Acquisition, MES-Manufacturing Execution
Systems)
Integração entre empresas, com o uso de sistemas de intercâmbio eletrônico de dado (EDI-Electronic Data
Interchange)
Toda a Internet e suas diversas aplicações de integração de empresas (e-procurement)
Aplicativos em arquitetura client-server, como os sistemas ERP-Enterprise Resource Planning
Novos automóveis, como o Citroen e seus 11 processadores embarcados (embedded systems)
 
E muitas outras.
 
As formas desta comunicação variam muito, desde o uso de interfaces seriais RS232, de rede Ethernet, wireless, etc.
 
Assim como no mundo dos humanos, a comunicação entre máquinas é governada por um protocolo. Um protocolo é
uma coleção de acordos, que devem ser observados por todos os envolvidos na comunicação. Veja por exemplo o
que acontece em uma sala de aula: quando um aluno deseja perguntar algo, levanta a mão, solicitando acesso ao
meio físico, o ar, e a “permissão para falar” (“token”). Ao terminar, o “token” retorna ao professor. De uma forma
simples, um protocolo de comunicação envolve dois tipos de protocolos:
Protocolo físico, envolvendo a definicação do meio físico (ar, cabo em par trançado, fibra ótica), a sinalização
(pressão acústica, nível de tensão, intensidade luminosa), a codificação do sinal (banda base, tipo de
modulação), conectores, etc. No caso dos humanos, definiu-se (pelo menos, por enquanto...) que o protocolo
físico utilizaria o ar como meio físico, com a sinalização em banda base utilizando pressão acústica. Um dia,
que sabe, estaremos usando ondas telepáticas...
Protocolo lógico, envolvendo a definição das mensagens que fluirão entre os participantes da comunicação.
Deve-se ter um acordo sobre o léxico, sintático e semântico. Por exemplo, não adianta você falar em Francês
quando seu interlocutor somente compreende Português; em outras palavras, apesar do léxico ser o mesmo, o
sintático e o semântico são diferentes.
 
Assim, não basta dizer que “os sistemas se comunicam através da interface serial RS232”, como comumente se
escuta. É necessário que o protocolo lógico também seja compreendido entre ambas as partes, para que a
comunicação realmente aconteça.
 
 
2.A pilha TCP-IP
 
2.1.O Modelo OSI-ISO
 
O modelo OSI-ISO (Open Systems Interconnection, produzido pela ISO-International Standards Organization) é
utilizado como referência para o projeto e a análise de protocolos de comunicação. Sua principal característica é
dividir as funcionalidades (que ele chama serviços) necessárias à comunicação em camadas, dividindo assim as
responsabilidades e permitindo que uma certa camada possa ter diferentes implementações (com diferentes
tecnologias ou fornecedores), mas ainda assim tendo-se a sua compatibilidade.
 
As setes camadas os serviços a serem prestados estão resumidos a seguir:
Fig.1. Modelo OSI-ISO
onde:
 
Camada Serviços
Física(1) • Transmissão de sequências de bits sobre meio físico
• Especifica : sinalização, codificação, conectores e pinagens,
meio físico, aspectos eletrônicos e mecânicos
• Domínio da engenharia eletrônica
• Não trata de correção de erros na transmissão
 
Enlace(2) • Organiza sequências de bits em conjuntos de bits chamados
frames
• Reconhece início e fim de frames
• Detecta perdas de frames e requisita retransmissão
 
Rede(3) • Encaminha informação da origem para o destino (roteamento)
• Controla fluxo de transmissão entre sub-redes (controle de
congestão)
• Funções de contabilização
• Estabelece esquema único de endereçamento independente da
sub-rede utilizada
• Permite conexão de sub-redes heterogêneas
 
Transporte(4) • Divide e reagrupa a informação binária em pacotes
• Garante a sequência dos pacotes
• Assegura a conexão confiável entre origem e destino da
comunicação
• Primeira camada que estabelece comunicação origem-destino
 
Sessão (5) • Gerencia sessões de comunicação
• Sessão é uma comunicação que necessita armazenar estados
• Estados são armazenados para permitir re-estabelecimento da
comunicação em caso de queda da comunicação
• Ex: Retomar transferências de arquivos
 
Apresentação(6) • Trata da representação dos dados em alto nível
• Adoção de sistema padronizado de representação de caracteres
• Adoção de códigos de representação numérica padrão
• Compressão de dados
• Codificação de dados
 
Aplicação (7) • Aplicações que oferecem os serviços ao usuário final
• Unificação de sistemas de arquivos e diretórios
• Correio eletrônico
• Login remoto
• Transferência de arquivos
• Execução remota
 
 
 
2.2.O protocolo TCP-IP
 
O protocolo TCP-IP foi criado nos anos 70, por encomenda do Departamento de Defesa dos Estados Unidos
(ARPA), com o objetivo militar de criação de uma rede em que não fosse necessário um ponto central de
coordenação, já que este poderia ser atacado em caso de guerra e destruído todo o sistema de comunicação.
Implementa de forma parcial o modelo OSI-ISO, como mostra a figura:
 
fig.2. Modelo OSI-ISO e TCP/IP
 
Pela figura, pode-se perceber que os níveis 1 e 2, responsáveis pelo acesso ao meio físico, podem ser implementados
de várias formas. Por exemplo, em sua casa, se você utiliza a acesso discado à Internet, tem a linha telefônica como
nivel 1 e o protocolo PPP (Point-To-Point Protocol) como nível 2.
 
No nível IP, cada computador conectado à rede mundial possui um endereço único, denominado endereço IP. Este é
formado por 4 bytes (valores de 0 a 255), como 143.107.106.20 e que corresponde a um nome único (no caso,
www.poli.usp.br).
 
O endereçamento IP é hierárquico, tendo-se as seguintes classes de endereçamento:
 
• A:0.X.X.X a 127.X.X.X, 128 redes de 16 milhões de computadores
• B:128.X.X.X a 191.X.X.X, 16 mil redes de 65 mil computadores
• C: 191.X.X.X a 223.X.X.X, 2 milhões de redes de 256 computadores
 
Duas implementações estão disponíveis no nivel de transporte (nivel 4): os protocolos TCP (Transport Control
Protocol) e UDP (User Datagram Protocol). As principais características destes protocolos estão listadas a seguir:
 
Protocolo Características
UDP • Oferece serviços de entrega de datagramas (pacotes)
• Não cuida do sequenciamento de pacotes
• Estaria “entre” a camada 3 e 4, pois não implementa sequenciamento
de pacotes
• Não implementa checagem e correção de erros (não confiável)
• Utilizado eficientemente em redes locais, que já possuem mecanismos
de checagem de erros em nível mais baixo
 
TCP • Oferece serviços de transmissão de streams
• Fragmenta os streams em pacotes e os entrega a camada IP
• Protocolo confiável com checagem de erros
• Implementa camada 4
• Mais complexo e mais lento que UDP
 
 
 
3.Sockets
 
O modelo OSI-ISO não define precisamente as interfaces entre as camadas, mas apenas os serviços a serem
prestados por cada uma. A interface entre a camada de Aplicação e a de Transporte foi definida, de forma
independente, pela Universidade da Califórnia em Berkeley, que projetou a interface chamada Sockets e pela AT&T,
que definiu o padrão TLI (Transport Layer Interface). A indústria adotou Sockets como padrão de fato.
 
3.1.Computação client-server
 
Na computação client-server, tem-se um processo Client (cliente) que requisitaum serviço (ou funcionalidade)
oferecido pelo processo Server (servidor). Client e Server podem estar no mesmo computador ou em computadores
distintos. Assim, por exemplo, quando o seu navegador de Internet (“browser”) requisita uma página
(http://www.poli.usp.br/mecatronica.html) está fazendo o papel de Client e o webserver, de Server. O serviço
envolvido é, justamente, o fornecimento da página web.
 
3.2.A interface Sockets
 
Um socket é um ponto de conexão entre a camada de Aplicação e a de Transporte (TCP ou UDP). Neste texto,
apenas a interface TCP será discutida, por sua mais larga aplicabilidade.
 
Do lado Server, definiu-se que a camada TCP teria 216 – 1 pontos de conexão, permitindo portanto que até cerca de
32000 diferentes Aplicações possam ser implementadas na mesma máquina. Este ponto de conexão é denominado
“port” (em Português, usa-se port ou porta). Cada Aplicação “escuta”[1] um socket, esperando por uma conexão e as
requisições dos diversos Clients. Uma mesma Aplicação pode ter, dependendo de como implementada, muitos
Clients simultaneamente.
 
Já o Client, para iniciar uma comunicação com o Server, deve inicialmente abrir uma conexão (lembre-se que o
protocolo TCP é orientado a conexão) e, a partir daí, pode enviar múltiplas requisições ao Server e deste, receber
respostas. Enquanto a conexão estiver ativa, tem-se uma comunicação bi-direcional entre Client e Server.
 
3.3.Sockets em Java
 
A linguagem Java possui uma bibliteca de funções no pacote java.net, voltada à comunicação por sockets.
 
As principais classes envolvidas e seus mais importantes métodos são:
 
java.net.ServerSocket representa a visão da comunicação do lado Server. Os seus principais métodos são:
 
ServerSocket(int port) throws IOException
Construtor. Recebe como parâmetro a porta a ser “escutada” pelo Server
 
accept() : Socket throws IOException
método que espera que uma conexão seja estabelecida. Retorna uma instância da classe Socket (ver a seguir) que
encapsula a comunicação propriamente dita entre client e server.
 
java.net.Socket representa uma conexão entre client e server. Seus principais métodos são:
 
Socket(String host, int port) throws UnknownHostException, IOException
Construtor. Recebe como parâmetros o endereço IP do server e port ao qual conectar-se.
 
getOutputStream() : OutputStream throws IOException
obtém uma instância do canal de saída (escrita) de informações. Ver a seguir a conceituação de OutputStream.
 
getInputStream() : InputStream throws IOException
obtém uma instância do canal de emtrada (leitura) de informações. Ver a seguir a conceituação de InputStream.
 
Para enviar ou receber informações, utilizam-se as classes InputStream e OutputStream. Entretanto, devido à
possibilidade de atrasos, normalmente são utilizadas as classes BufferedInputStream e BufferedOutputStream, que
fornecem um “buffer” (área de armazenamento temporário) que evita as perdas de caracteres por “over run” (quando
a saída está lenta e perde-se um caracter, escrevendo um novo caracter sobre outro que ainda não foi enviado) ou
“under run” (idem, na leitura). Estas classes pertencem ao pacote java.io. Estas classes são utilizadas em todas as
situações de entrada e saída de dados, como as relacionadas com arquivos, teclado, etc.
 
java.io.BufferedInputStream representa um “stream” (fluxo de dados contínuo) de leitura. Seus principais
métodos são:
 
BufferedInputStream(InputStream in)
Construtor. Exige como parâmetro um InputStream; neste caso, será exatamente o retorno de
Socket.getInputStream()
 
read() : int throws IOException
Leitura de um caracter. Retorna -1 se o “stream” chegou ao final.
 
java.io.BufferedOutputStream representa um “stream” de escrita ou saída de dados. Seus principais métodos são:
 
BufferedOutputStream(OutputStream out)
Construtor. Exige como parâmetro um OutputStream; neste caso, será exatamente o retorno de
Socket.getOutputStream()
 
write(int b) : void throws IOException
Escrita de um caracter.
 
write(byte[] b) : void throws IOException
Escrita de um vetor de caracteres.
 
flush() : void throws IOException
Força a saída dos dados buferizados. Até o flush(), os dados são somente armazenados no buffer de saída e somente
são efetivamente enviados pela chamada deste método.
 
4.Parte Experimental
 
4.1.Comunicação Client-Server
 
Considere o programa do Anexo 1. Analise-o, verificando que contém a parte Client e Server, reunidas em um único
arquivo por simplicidade didática, encerradas nas classes SimpleClient e SimpleServer, respectivamente.
 
No SimpleServer, observe a seguinte sequência de processamento:
É criado um ServeSocket para “escutar” a porta SERVER_SOCKET (no caso, foi escolhido arbitrariamente a
porta 2001)
O Server é colocado para “escutar” as requisições (chamada do método ServerSocket.accept())
Ao receber uma conexão, o método ServerSocket.accept() retorna uma instância de Socket, que representa esta
conexão
Um BufferedInputStream é criado para a leitura dos dados
Um while { } faz a leitura dos dados, caracter a caracter, terminando quando a chamada de bis.read() retorna -1
que significa que a conexão foi desfeita pelo client. Cada caracter recebido é impresso na console.
 
No SimpleClient, observe a seguinte sequência de processamento:
É criada uma conexão com o server, com a instanciação da classe Socket informando-se HOST e PORT (no
caso, HOST=”localhost” e PORT=2001)
Obtém-se um canal de escrita de dados para este Socket (note que, neste caso inicial, foi usado um canal sem
bufferização)
Um while { } faz enviar valores inteiros de 0 a 128 ao server.
 
Atividades:
a.Compile o programa
b.Abra duas janelas DOS, executando em uma o server:
c:\> java SimpleServer
 
e, na outra, o client:
 
c:\>java SimpleClient
 
c.Observe que o server recebe os dados enviados pelo Client
d.Obtenha o endereço IP do computador de algum colega, usando
 
c:\>netstat –nr
 
Altere a constante HOST na classe SimpleClient, compile e execute novamente o client. Provavelmente não
funcionará, por causa do “over-run”. Assim, você precisará alterar o seu Client, para utilizar o
BufferedOutputStream. Não se esqueça do flush() para enviar realmente os dados! Ficará algo como:
 
 Socket s = new Socket(HOST, PORT);
 BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
 int i = 0;
 while (i < 128) {
 bos.write(i++);
 } // while 
 bos.flush();
 
Perceba que agora os dados não são mais enviados ao seu Server mas ao Server de seu colega!
 
d.Altere o programa, para que o Server adicione 100 a cada valor recebido e o envie de volta ao Client, que deve
também ser capaz de ler as respostas enviadas pelo Server e imprimí-las.
 
 
4.2.Aplicação de sockets: um WebServer
 
A base da Internet são os servidores Web, capazes de enviar uma página HTML (Hyper Text Markup Language) ao
seu navegador (“browser”).
 
O protocolo da camada de aplicação (ou seja, entre o webserver e o browser) é conhecido como HTTP (Hyper Text
Transport Protocol). Quando você digita em seu navegador uma requisição de acesso, como
 
http://www.poli.usp.br/mecatronica.html
 
o seu browser : (1)abre um socket para www.poli.usp.br e (2) envia uma string contendo
“GET ./mecatronica.html HTTP/1.1 \n\n” onde “\n” corresponde à sequência de caracteres ASCII 0x0D 0x0A ou CR
LF.
 
O webserver, recebendo esta requisição, obtém o nome do arquivo (no caso “mecatronica.html”) e lê de seu disco
local este arquivo, enviando-o ao browser. Este arquivo deve estar formatado como uma página HTML.
 
Veja o programa do Anexo 2, que é uma implementação simples (mas funcional!) de um WebServer. Analise-o,
notando que:
Um ServerSocket é criado, indicando que a aplicação deseja escutar a porta SERVER_SOCKET (no caso,
2001).Ao receber uma conexão, cria uma instância de HttpResponder, cujo método HttpResponder.processRequests()
é responsável por :
Ler os caracteres enviados pelo browser (HttpResponder.getRequest())
Obter, da requisição recebida, o nome do arquivo HTML desejado (HttpResponder.getFileName())
Ler o arquivo e enviar, via socket, os seu conteúdo (HttpResponder.sendFile())
 
Atividades
a.Crie, no diretório onde se encontra o programa SimpleWebServer.java, um arquivo HTML (chame-o, por exemplo,
“pagina.html”) como por exemplo:
 
<html>
<body>pagina inicial
</body>
</html>
 
b.Modifique, no SimpleWebServer.java, a linha que indica onde estão as páginas HTML, modificando a linha onde
se define a variável BASE_DIR. Não se esqueça de manter as barras normais (e não invertidas, como é normal em
MS Windows) e colocar uma barra no final. Compile e execute o SimpleWebServer
 
c.Inicie o navegador e digite na barra de navegação
 
http://localhost:2001/pagina.html
 
Observe que foi designada a porta 2001, já que é esta a porta que o nosso SimpleWebServer está configurado para
“escutar”.
 
c.Veja no seu navegador que a página HTML será exibida.
 
d.Agora, digite no seu navegador uma linha semelhante, substituindo “localhost” pelo endereço IP da máquina de
algum de seus colegas. Verifique que você é capaz de ver a página que ele está disponibilizando. É assim que
funciona a Internet!
 
 
Referências
 
[Comer, 1994] Comer, D.E.; Stevens, D.L. “Internetworking with TCP/IP”. Prentice Hall, 1994.
 
[UNESP, 2003] UNESP. “Apresentação sobre modelo OSI-ISO e TCP/IP”. www.rc.unesp.br/polo/tcpip.ppt
 
 
Anexo 1: SimpleServer e SimpleClient
 
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.String;
 
class SimpleServer {
 
 static final int SERVER_SOCKET = 2001;
 
 public static void main(String[] args) {
 try {
 ServerSocket ss = new ServerSocket(SERVER_SOCKET);
 while (true) {
 Socket s = ss.accept();
 BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
 int ch;
 while ( (ch = bis.read()) != -1) {
 System.out.println("" + ch);
 }
 } // while 
 } catch(Exception e) {e.printStackTrace(); }
 } 
} // SimpleServer
 
class SimpleClient {
 
 static final int PORT = 2001;
 static final String HOST = "localhost";
 
 public static void main(String[] args) {
 try {
 Socket s = new Socket(HOST, PORT);
 OutputStream os = s.getOutputStream();
 int i = 0;
 while (i < 128) {
 os.write(i++);
 } // while 
 } catch(Exception e) {e.printStackTrace(); }
 } 
} // SimpleClient
 
Anexo 2: SimpleWebServer
 
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.String;
import java.util.Date;
import java.util.StringTokenizer;
import java.io.FileInputStream;
 
public class SimpleWebServer {
 
 static final int SERVER_SOCKET = 2001;
 
 public static void main(String[] args) {
 try {
 ServerSocket ss = new ServerSocket(SERVER_SOCKET);
 while (true) {
 Socket s = ss.accept();
 HttpResponder hr = new HttpResponder(s);
 hr.processRequests();
 } // while 
 } catch(Exception e) {e.printStackTrace(); }
 } 
 
 
} // SimpleServer 
 
class HttpResponder {
 Socket m_Socket = null;
 static String BASE_DIR=”c:/mecatronica/”
 
 HttpResponder(Socket s) {
 m_Socket = s;
 } //HttpResponder
 
 void processRequests() {
 try {
 String request = getRequest();
 System.out.println(request);
 String file = getFileName(request);
 System.out.println(file);
 sendFile(file);
 } catch (Exception e) { e.printStackTrace(); } 
 } // processRequests 
 
 String getFileName(String request) {
 StringTokenizer st = new StringTokenizer(request);
 st.nextToken();
 return st.nextToken();
 } // getFileName
 
 void sendFile(String filename) throws Exception{
 OutputStream os = m_Socket.getOutputStream();
 FileInputStream fis = new FileInputStream(BASE_DIR + filename);
 byte[] bytes = new byte[2048];
 fis.read(bytes);
 os.write(bytes);
 os.close();
 } // sendFile
 
 String getRequest() throws Exception {
 BufferedInputStream bis = new BufferedInputStream(m_Socket.getInputStream());
 int ch;
 String request = "";
 byte[] buf = new byte[1];
 while ( (ch = bis.read()) != -1) {
 //System.out.println("" + ch);
 if (ch == 13) {
 return request;
 } else {
 buf[0] = (byte)ch;
 request += new String(buf);
 }
 } // while 
 return null;
 } // getRequest
 } // HttpResponder 
 
[1]
 A expressão “escutar um socket” é uma tradução literal do Inglês (“to listen to a socket”) e é utilizada no meio técnico.

Continue navegando