Programação de Sockets Objetivo: aprender a construir aplicações cliente/servidor que se comunicam usando sockets API de Sockets introduzida no BSD4.1 UNIX, 1981 sockets são explicitamente criados, usados e liberados pelas aplicações paradigma cliente/servidor dois tipos de serviço de transporte via socket API: datagrama não confiável confiável, orientado a fluxo de bytes socket uma interface local, criada e possuída pelas aplicações controlada pelo OS uma porta através qual os processos de aplicação podem tanto enviar quanto receber mensagens de e para outro processo de aplicação (local ou remoto) Cap. 2: Camada de Aplicação 1
Programação de Sockets com TCP Socket: uma porta entre o processo de aplicação e o protocolo de transporte fim-a-fim (UDP ou TCP) serviço TCP: transferência confiável de bytes de um processo para outro controlado pelo criador da aplicação controlado pelo sistema operacional processo socket TCP com buffers, variáveis internet processo socket TCP com buffers, variáveis controlado pelo criador da aplicação controlado pelo sistema operacional host ou servidor host ou servidor Cap. 2: Camada de Aplicação 2
Programação de Sockets com TCP Cliente deve contactar o servidor processo servidor já deve estar executando antes de ser contactado servidor deve ter criado um socket (porta) que aceita o contato do cliente Como o cliente contacta o servidor: criando um socket TCP local especificando endereço IP e número da porta do processo Quando o cliente cria o socket: cliente TCP estabelece conexão com o TCP do servidor Quando contactado pelo cliente, o TCP do servidor cria um novo socket para o processo servidor comunicar-se com o cliente permite ao servidor conversar com múltiplos clientes ponto de vista da aplicação TCP fornece a transferência confiável (fluxo de bytes ordenados) ( pipe ) entre o cliente e o servidor Cap. 2: Camada de Aplicação 3
Programação de Sockets com TCP Exemplo de aplicação cliente-servidor: cliente lê uma linha da entrada padrão do sistema (stream infromuser), envia para o servidor via socket (stream outtoserver) servidor lê a linha do socket servidor converte linha para letras maiúsculas e envia de volta ao cliente cliente lê a linha modificada através do sockete (stream infromserver) process o cliente stream de saída: seqüência de bytes input stream para fora do processo output stream teclado infromuser outtoserver para rede monitor stream de entrada: seqüência de bytes para dentro do processo infromserver TCP socket clientsocket cliente da rede input stream TCP socket Cap. 2: Camada de Aplicação 4
Interação Cliente/servidor: TCP Servidor (executando em hostid) cria socket, porta=x, para solicitação entrante: welcomesocket = ServerSocket() TCP espera por pedido estab. de conexão de conexão entrante connectionsocket = welcomesocket.accept() lê pedido de connectionsocket escreve resposta para connectionsocket fecha connectionsocket Cliente cria socket, conecta com hostid, porta=x: clientsocket = Socket() envia pedido usando clientsocket lê resposta de clientsocket fecha clientsocket Cap. 2: Camada de Aplicação 5
Exemplo: cliente Java (TCP) import java.io.*; import java.net.*; class TCPClient { Cria stream de entrada Cria socket cliente, conecta ao servidor Cria stream de saída ligada ao socket public static void main(string argv[]) throws Exception { String sentence; String modifiedsentence; BufferedReader infromuser = new BufferedReader(new InputStreamReader(System.in)); Socket clientsocket = new Socket("hostname", 6789); DataOutputStream outtoserver = new DataOutputStream(clientSocket.getOutputStream()); Cap. 2: Camada de Aplicação 6
Exemplo: cliente Java (TCP), cont. Cria stream de entrada ligada ao socket BufferedReader infromserver = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); sentence = infromuser.readline(); Envia linha para o servidor Lê linha do servidor outtoserver.writebytes(sentence + '\n'); modifiedsentence = infromserver.readline(); System.out.println("FROM SERVER: " + modifiedsentence); clientsocket.close(); Cap. 2: Camada de Aplicação 7
Exemplo: servidor Java (TCP) import java.io.*; import java.net.*; class TCPServer { Cria socket de aceitação na porta 6789 Espera, no socket de aceitação por contato do cliente Cria stream de entrada, ligado ao socket public static void main(string argv[]) throws Exception { String clientsentence; String capitalizedsentence; ServerSocket welcomesocket = new ServerSocket(6789); while(true) { Socket connectionsocket = welcomesocket.accept(); BufferedReader infromclient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); Cap. 2: Camada de Aplicação 8
Exemplo: servidor Java (cont) Cria stream de saída, ligado ao socket Lê linha do socket DataOutputStream outtoclient = new DataOutputStream(connectionSocket.getOutputStream()); clientsentence = infromclient.readline(); capitalizedsentence = clientsentence.touppercase() + '\n'; Escreve linha para o socket outtoclient.writebytes(capitalizedsentence); Fim do while loop, retorne e espere por outra conexão do cliente Cap. 2: Camada de Aplicação 9
Programaçaõ de Sockets com UDP UDP: não há conexão entre o cliente e o servidor não existe apresentação (handshaking) transmissor envia explicitamente endereço IP e porta de destino em cada mensagem servidor deve extrair o endereço IP e porta do transmissor de cada datagrama recebido UDP: dados transmitidos podem ser recebidos foram de ordem ou perdidos ponto de vista da aplicação UDP fornece a transferência não confiável de grupos de bytes ( datagramas ) entre o cliente e o servidor Cap. 2: Camada de Aplicação 10
Interação Cliente/servidor: UDP Servidor (executando em hostid) cria socket, porta=x, para solicitação entrante: serversocket = DatagramSocket() lê pedido de: serversocket Cliente cria socket, clientsocket = DatagramSocket() Cria endereço (hostid, port=x), envia datagrama de pedido usando clientsocket escreve resposta para serversocket especificando endereço do host cliente e número da porta lê resposta de clientsocket fecha clientsocket Cap. 2: Camada de Aplicação 11
Exemplo: cliente Java (UDP) teclado monitor process Process o cliente Saída: envia pacote (TCP enviaria byte stream ) stream de entrada pacote UDP infromuser sendpacket receivepacket pacote UDP Entrada: recebe pacote (TCP receberia byte stream ) socket UDP clientsocket cliente UDP socket para rede da rede Cap. 2: Camada de Aplicação 12
Exemplo: cliente Java (UDP) import java.io.*; import java.net.*; Cria stream de entrada Cria socket cliente Traduz nome do host para endereço IP usando DNS class UDPClient { public static void main(string args[]) throws Exception { BufferedReader infromuser = new BufferedReader(new InputStreamReader(System.in)); DatagramSocket clientsocket = new DatagramSocket(); InetAddress IPAddress = InetAddress.getByName("hostname"); byte[] senddata = new byte[1024]; byte[] receivedata = new byte[1024]; String sentence = infromuser.readline(); senddata = sentence.getbytes(); Cap. 2: Camada de Aplicação 13
Exemplo: cliente Java (UDP), cont. Cria datagrama com dados a enviar, tamanho, endereço IP e porta Envia datagrama para servidor Lê datagrama do servidor DatagramPacket sendpacket = new DatagramPacket(sendData, senddata.length, IPAddress, 9876); clientsocket.send(sendpacket); DatagramPacket receivepacket = new DatagramPacket(receiveData, receivedata.length); clientsocket.receive(receivepacket); String modifiedsentence = new String(receivePacket.getData()); System.out.println("FROM SERVER:" + modifiedsentence); clientsocket.close(); Cap. 2: Camada de Aplicação 14
Exemplo: servidor Java (UDP) import java.io.*; import java.net.*; Cria socket datagrama na porta 9876 Cria espaço para datagramas recebidos Recebe datagram a class UDPServer { public static void main(string args[]) throws Exception { DatagramSocket serversocket = new DatagramSocket(9876); byte[] receivedata = new byte[1024]; byte[] senddata = new byte[1024]; while(true) { DatagramPacket receivepacket = new DatagramPacket(receiveData, receivedata.length); serversocket.receive(receivepacket); Cap. 2: Camada de Aplicação 15
Exemplo: servidor Java, (cont.) Obtém endereço IP e número da porta do transmissor String sentence = new String(receivePacket.getData()); InetAddress IPAddress = receivepacket.getaddress(); int port = receivepacket.getport(); String capitalizedsentence = sentence.touppercase(); Cria datagrama para enviar ao cliente Escreve o datagrama para dentro do socket senddata = capitalizedsentence.getbytes(); DatagramPacket sendpacket = new DatagramPacket(sendData, senddata.length, IPAddress, port); serversocket.send(sendpacket); Termina o while loop, retorna e espera por outro datagrama Cap. 2: Camada de Aplicação 16
Programação de Sockets: referências tutorial sobre sockets em linguagem C (audio/slides): Unix Network Programming (J. Kurose), http://manic.cs.umass.edu Tutoriais sobre sockets em Java: Socket Programming in Java: a tutorial, http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets Cap. 2: Camada de Aplicação 17
Construção de um Servidor Web Simplificado Ingredientes: Protocolo HTTP + Sockets Funcionalidade: Trata apenas uma requisição HTTP Aceita e interpreta a requisição Obtém o arquivo requisitado a partir do sistema de arquivos local (do servidor Web) Cria uma mensagem de resposta HTTP: Linhas de cabeçalho + arquivo requisitado Envia a resposta diretamente para o cliente Fecha conexão e termina Cap. 2: Camada de Aplicação 18
Construção de um Servidor Web Simplificado Cliente: Navegador Web padrão Netscape, IE, Konqueror, etc. Exemplo de requisição: URL: http://somehost.somewhere.br:6789/somefile.ht ml host e porta: usados p/ estab. conexão com servidor Requisição: GET /somefile.html HTTP/1.0 Cap. 2: Camada de Aplicação 19
WebServer.java (1) import java.io.*; import java.net.*; import java.util.*; class WebServer { public static void main (String argv[]) throws Exception { Stream para receber dados via socket String requestmessageline; ServerSocket listensocket = new ServerSocket(6789); Socket connectionsocket = listensocket.accept(); BufferedReader infromclient = new BufferedReader (new InputStreamReader( connectionsocket.getinputstream())); Socket para espera de conexões Socket de conexão c/ cliente Cap. 2: Camada de Aplicação 20
Separa os tokens da requisição Verifica se comando é GET WebServer.java (2) Obtém o tamanho do arquivo DataOutputStream outtoclient = new DataOutputStream( connectionsocket.getoutputstream()); requestmessageline = infromclient.readline(); StringTokenizer tokenizedline = new StringTokenizer( requestmessageline); if (tokenizedline.nexttoken().equals( GET )){ filename = tokenizedline.nexttoken(); if (filename.startswith( / ) == true) filename = filename.substring(1); File file = new File(fileName); int numofbytes = (int) file.length(); Stream para enviar dados através do socket Lê requisição do cliente Obtém o nome do arquivo Cap. 2: Camada de Aplicação 21
WebServer.java (3) Lê o arquivo requisitado Envia a primeira linha do cabeçalho da resposta Segunda linha (content type) depende do tipo do arquivo requisitado (jpeg ou gif) FileInputStream infile = new FileInputStream(fileName); byte [] fileinbytes = new byte[numofbytes]; infile.read(fileinbytes); outtoclient.writebytes( HTTP/1.0 200 Document Follows\r\n ); if (filename.endswith(.jpg )) outtoclient.writebytes( Content-Type: image/jpeg\r\n ); if (filename.endswith(.gif )) outtoclient.writebytes( Content-Type: image/gif\r\n ); Cap. 2: Camada de Aplicação 22
WebServer.java (4) Envia a 3a. linha do cabeçalho Linha em branco para separar o cabeçalho do corpo da msg outtoclient.writebytes( Content-Length: + numofbytes + \r\n ); outtoclient.writebytes( \r\n ); outtoclient.write(fileinbytes, 0, numofbytes); connectionsocket.close(); else System.out.println( Bad Request Message ); Envia o arquivo requisitado Fecha a conexão com o cliente Cap. 2: Camada de Aplicação 23
WebServer.java: O que Falta? Aceitar múltiplas requisições Cada requisição processada por uma thread diferente Tratar outros tipos de conteúdo (linha de cabeçalho Content-type:) Suporte para demais comandos (POST, HEAD) Suporte para demais tipos de mensagem de resposta (Bad request, Not found, etc.) O que mais? Cap. 2: Camada de Aplicação 24