INF01018 – Aula Prática 1 – Cliente-Servidor e Multicast Lucas Mello Schnorr, Alexandre Silva Carı́ssimi {lmschnorr,asc}@inf.ufrgs.br http://www.inf.ufrgs.br/∼lmschnorr/ad/ INF01018 – Sistemas Operacionais Distribuı́dos e de Redes Sala 102 – Prédio 67 – 05 Setembro 2006 1 / 30 Roteiro 1 Introdução 2 Cliente-Servidor 3 Multicast 4 Referências 2 / 30 Introdução Dar suporte às aulas teóricas 04 e 05 Utilização de exemplos com código fonte Duas linguagens de programação: Java e C Programas Cliente/Servidor e Multicast Download de Exemplos http://www.inf.ufrgs.br/∼lmschnorr/ad/aula1.tar.gz 3 / 30 Introdução – Parte do Cliente/Servidor Do lado do servidor Recebe comandos dos clientes Se comando for igual a hora, enviar hora local ao cliente Se comando não for conhecido, envia mensagem ao cliente avisando Do lado do cliente Cria uma datagrama com o comando Envia ao servidor Aguarda uma resposta 4 / 30 Introdução – Parte do Multicast Dois programas Programa Receptor Cria um socket multicast Faz bind desse socket a um endereço multicast Aguarda mensagens do socket e imprime na tela Programa Enviador Cria um socket multicast Entra no grupo multicast Envia uma mensagem ao grupo 5 / 30 Cliente-Servidor UDP Serviço orientado a Datagramas Sem confirmação de recebimento ou retentativas Do lado do servidor Recebe comandos dos clientes Se comando for igual a hora, enviar hora local ao cliente Se comando não for conhecido, envia mensagem ao cliente avisando Do lado do cliente Cria uma datagrama com o comando Envia ao servidor Aguarda uma resposta 6 / 30 UDP usando a linguagem C Principais funções socket (int domain, int type, int protocol) bind (int sockfd, struct sockaddr *addr, socklen t len) recvfrom (int s, void *buf, size t len, int flags, struct sockaddr *from, socklen t *fromlen) sendto (int s, const void *buf, size t len, int flags, const struct sockaddr *to, socklen t tolen) 7 / 30 Cliente-Servidor UDP em C – 1/3 Códigos retirados do arquivo ServidorUDP.c 30 31 32 33 / ∗ c r i a r s o c k e t UDP para r e c e b e r ou e n v i a r datagramas ∗ / i f ( ( sock = socket ( PF INET , SOCK DGRAM, IPPROTO UDP ) ) < 0 ) { p e r r o r ( ” sock ( ) f a l h o u ” ) ; } 35 36 37 38 39 / ∗ c o n s t r u i r a e s t r u t u r a de endereco l o c a l ∗ / memset (& echoServAddr , 0 , s iz e o f ( echoServAddr ) ) ; echoServAddr . s i n f a m i l y = AF INET ; echoServAddr . s i n a d d r . s a d d r = h t o n l ( INADDR ANY ) ; echoServAddr . s i n p o r t = htons ( numeroPorta ) ; 41 42 43 44 45 / ∗ Bind ao endereco l o c a l ∗ / i f ( bind ( sock , ( s t r u c t sockaddr ∗ ) & echoServAddr , s iz e o f ( echoServAddr ) ) < 0 ) { perror ( ” bind ( ) falhou ” ) ; } 8 / 30 Cliente-Servidor UDP em C – 2/3 Códigos retirados do arquivo ServidorUDP.c 47 48 49 50 51 52 53 54 55 56 68 69 70 71 72 73 while ( 1 ) { / ∗ e s p e r a r mensagem de alguem ∗ / c l i A d d r L e n = s iz e o f ( echoClntAddr ) ; i f ( ( recvMsgSize = recvfrom ( sock , echoBuffer , ECHOMAX, 0 , ( s t r u c t sockaddr ∗ ) & echoClntAddr , & c l i A d d r L e n ) ) < 0 ) { p e r r o r ( ” r e c v fr o m ( ) f a l h o u ” ) ; } p r i n t f ( ” Recebeu c l i e n t e %s\n ” , i n e t n t o a ( echoClntAddr . s i n a d d r ) ) ; p r i n t f ( ” ==> [%s ] %d\n ” , echoBuffer , c l i A d d r L e n ) ; / ∗ e n v i a r a HORA para o c l i e n t e ∗ / i n t bytesEnviados = sendto ( sock , t i m e s t r i n g , s iz e o f ( t i m e s t r i n g ) , 0 , ( s t r u c t sockaddr ∗ ) & echoClntAddr , s iz e o f ( echoClntAddr ) ) ; p r i n t f ( ” enviando %d\n ” , bytesEnviados ) ; 9 / 30 Cliente-Servidor UDP em C – 3/3 Códigos retirados do arquivo ClienteUDP.c 36 37 38 39 / ∗ c r i a r um s o c k e t UDP ∗ / i f ( ( sock = socket ( PF INET , SOCK DGRAM, IPPROTO UDP ) ) < 0 ) { p e r r o r ( ” socket ( ) falhou ” ) ; } 41 42 43 44 45 / ∗ c o n s t r u i r a e s t r u t u r a de endereco do s e r v i d o r ∗ / memset (& echoServAddr , 0 , s iz e o f ( echoServAddr ) ) ; echoServAddr . s i n f a m i l y = AF INET ; echoServAddr . s i n a d d r . s a d d r = i n e t a d d r ( nomeServidor ) ; echoServAddr . s i n p o r t = htons ( numeroPorta ) ; 47 48 49 50 / ∗ e n v i a r o comando para o s e r v i d o r ∗ / sendto ( sock , mensagem , tamanhoMensagem+ 1 , 0 , ( s t r u c t sockaddr ∗ ) & echoServAddr , s iz e o f ( echoServAddr ) ) ; 52 53 54 55 / ∗ r e c e b e r uma r e s p o s ta ∗ / fromSize = s iz e o f ( fromAddr ) ; r e s p S tr i n g L e n = recvfrom ( sock , echoBuffer , ECHOMAX, 0 , ( s t r u c t sockaddr ∗ ) & fromAddr , & fromSize ) ; 10 / 30 UDP usando a linguagem Java Classes utilizadas DatagramSocket new DatagramSocket (int porta) DatagramPacket new DatagramPacket (byte[] b, int length) new DatagramPacket (byte[] buf, int length, InetAddress address, int port) 11 / 30 Cliente-Servidor UDP em Java – 1/3 Códigos retirados do arquivo ServidorUDP.java 18 19 20 / ∗ I n i c i a l i z a c a o do s o c k e t UDP ∗ / s o c k e t = new DatagramSocket ( new I n t e g e r ( numeroPorta ) . i n t V a l u e ( ) ) ; 22 23 24 25 26 27 28 29 / ∗ Laco de recebimento de datagramas ∗ / while ( t r u e ) { request = n u l l ; reply = nu ll ; b u f = new b y te [ 1 0 2 4 ] ; 31 32 33 34 35 36 / ∗ Recepcao bloqueante dos dados ∗ / socket . receive ( request ) ; / ∗ Preparacao do Datagrama de Recepcao ∗ / r e q u e s t = new DatagramPacket ( buf , b u f . l e n g t h ) ; / ∗ Recuperacao do comando ∗ / comando = new S t r i n g ( r e q u e s t . getData ( ) , 0 , r e q u e s t . getLength ( ) ) ; 12 / 30 Cliente-Servidor UDP em Java – 2/3 Códigos retirados do arquivo ServidorUDP.java 43 44 45 46 47 56 57 / ∗ C r i a datagrama com a r e s p o s ta ∗ / r e p l y = new DatagramPacket ( hora . g e tB y te s ( ) , hora . g e tB y te s ( ) . l e n g th , r e q u e s t . getAddress ( ) , request . getPort ( ) ) ; / ∗ Envia r e s p o s ta p e l o s o c k e t UDP ∗ / s o c k e t . send ( r e p l y ) ; 13 / 30 Cliente-Servidor UDP em Java – 3/3 Códigos retirados do arquivo ClienteUDP.java 20 21 / ∗ I n i c i a l i z a c a o de s o c k e ts UDP com Datagrama ∗ / s o c k e t = new DatagramSocket ( ) ; 23 24 25 26 27 28 29 / ∗ Configuracao a p a r t i r dos parametros ∗ / In e tA d d r e s s h o s t = In e tA d d r e s s . getByName ( nomeServidor ) ; s e r v e r P o r t = new I n t e g e r ( numeroPorta ) . i n t V a l u e ( ) ; b y te [ ] m = mensagemEnviar . g e tB y te s ( ) ; 31 32 / ∗ Envio p r o p r i a m e n te d i t o ∗ / s o c k e t . send ( r e q u e s t ) ; 34 35 36 37 38 / ∗ Preparacao do Pacote Datagrama para Recepcao ∗ / r e p l y = new DatagramPacket ( buf , b u f . l e n g t h ) ; / ∗ Criacao do Pacote Datagrama para Envio ∗ / r e q u e s t = new DatagramPacket (m, m. l e n g th , host , s e r v e r P o r t ) ; / ∗ Recepcao do r e t o r n o ∗ / socket . receive ( r e p l y ) ; 14 / 30 Cliente-Servidor em TCP TCP Orientado a conexão (stream) Confiabilidade e Integridade Menos desempenho na comunicação 15 / 30 TCP usando a linguagem C Principais funções socket (int domain, int type, int protocol) bind (int sockfd, struct sockaddr *addr, socklen t len) listen (int sockfd, int backlog) accept (int sockfd, struct sockaddr *addr, socklen t *addrlen); send (int s, const void *buf, size t len, int flags); recv (int s, void *buf, size t len, int flags); connect (int sockfd, const struct sockaddr *serv addr, socklen t addrlen); 16 / 30 Cliente-Servidor TCP em C – 1/4 Códigos retirados do arquivo ServidorTCP.c 36 37 38 39 40 / ∗ Criacao do s o c k e t TCP para r e c e b e r conexoes ∗ / i f ( ( servSock = socket ( PF INET , SOCK STREAM , IPPROTO TCP)) <0){ p e r r o r ( ” socket ( ) falhou ” ) ; exit (1); } 43 44 45 46 47 / ∗ c o n s tr u c a o do endereco de conexao ∗ / memset (& echoServAddr , 0 , s iz e o f ( echoServAddr ) ) ; echoServAddr . s i n f a m i l y = AF INET ; echoServAddr . s i n a d d r . s a d d r = h t o n l ( INADDR ANY ) ; echoServAddr . s i n p o r t = htons ( numeroPorta ) ; 49 50 51 52 53 54 / ∗ Bind ao endereco l o c a l ∗ / i f ( bind ( servSock , ( s t r u c t sockaddr ∗ ) & echoServAddr , s iz e o f ( echoServAddr ) ) < 0 ) { perror ( ” bind ( ) falhou ” ) ; exit (1); } 17 / 30 Cliente-Servidor TCP em C – 2/4 Códigos retirados do arquivo ServidorTCP.c 57 58 59 60 61 /∗ l i s t e n ∗/ i f ( l i s t e n ( servSock , MAXPENDING) < 0 ) { perror ( ” l i s t e n ( ) falhou ” ) ; exit (1); } 64 65 66 67 68 69 70 71 72 while ( 1 ) { / ∗ esperando conexoes com accept ∗ / c l n t L e n = s iz e o f ( echoClntAddr ) ; i f ( ( c l n t S o c k = accept ( servSock , ( s t r u c t sockaddr ∗ ) & echoClntAddr , &clntLen ) ) < 0 ) { p e r r o r ( ” accept ( ) f a l h o u ” ) ; exit (1); } 18 / 30 Cliente-Servidor TCP em C – 3/4 Códigos retirados do arquivo ServidorTCP.c 74 75 76 77 78 79 80 81 82 / ∗ c l n t S o c k e s ta conectado a um c l i e n t e ∗ / p r i n t f ( ” Tratando c l i e n t e %s\n ” , i n e t n t o a ( echoClntAddr . s i n a d d r ) ) ; while ( 1 ) { i f ( ( tamanhoRecebido = recv ( c l n tS o c k , comando , RCVBUFSIZE , 0 ) ) < 0 ) { p e r r o r ( ” r e c v ( ) f a l h o u \n ” ) ; exit (1); } 94 95 / ∗ enviando dados ao c l i e n t e ∗ / i n t k = send ( c l n tS o c k , t i m e s t r i n g , s iz e o f ( t i m e s t r i n g ) , 0 ) ; 19 / 30 Cliente-Servidor TCP em C – 4/4 Códigos retirados do arquivo ClienteTCP.c 34 35 / ∗ Criacao do Socket TCP ∗ / sock = socket ( PF INET , SOCK STREAM , IPPROTO TCP ) ; 37 38 39 40 41 / ∗ c o n s tr u c a o do endereco de conexao ∗ / memset (& echoServAddr , 0 , s iz e o f ( echoServAddr ) ) ; echoServAddr . s i n f a m i l y = AF INET ; echoServAddr . s i n a d d r . s a d d r = i n e t a d d r ( e n d e r e c o IP S e r v i d o r ) ; echoServAddr . s i n p o r t = htons ( numeroPorta ) ; 43 44 45 46 47 48 / ∗ Conectando ao s e r v i d o r ∗ / i f ( connect ( sock , ( s t r u c t sockaddr ∗ ) & echoServAddr , s iz e o f ( echoServAddr ) ) < 0 ) { p e r r o r ( ” connect ( ) f a l h o u : ” ) ; exit (1); } 20 / 30 TCP usando a linguagem Java Principais Classes ServerSocket (int port) PrintWriter (OutputStream out, boolean autoFlush) BufferedReader (Reader in) 21 / 30 Cliente-Servidor TCP em Java – 1/2 Códigos retirados do arquivo ServidorTCP.java 20 21 22 / ∗ I n i c i a l i z a c a o do s e r v e r s o c k e t TCP ∗ / s e r v e r S o c k e t = new ServerSocket ( new I n t e g e r ( numeroPorta ) . i n t V a l u e ( ) ) ; 24 25 26 while ( t r u e ) { / ∗ Espera por um c l i e n t e ∗ / c l i e n t S o c k e t = s e r v e r S o c k e t . accept ( ) ; 29 30 31 32 33 / ∗ Preparacao dos f l u x o s de e n tr a d a e s a i d a ∗ / o u t = new P r i n t W r i t e r ( c l i e n t S o c k e t . getOutputStream ( ) , true ) ; i n = new BufferedReader ( new InputStreamReader ( c l i e n t S o c k e t . g e tIn p u tS tr e a m ( ) ) ) ; 35 36 / ∗ Recuperacao dos comandos ∗ / while ( ( comando = i n . r e a d L i n e ( ) ) ! = n u l l ) { 42 43 / ∗ Escreve na s a i d a a ’ hora ’ ∗ / o u t . p r i n t l n ( hora ) ; 22 / 30 Cliente-Servidor TCP em Java – 2/2 Códigos retirados do arquivo ClienteTCP.java 17 18 19 / ∗ I n i c i a l i z a c a o de s o c k e t TCP ∗ / socket = new Socket ( nomeServidor , new I n t e g e r ( numeroPorta ) . i n t V a l u e ( ) ) ; 21 22 23 24 / ∗ I n i c i a l i z a c a o dos f l u x o s de e n tr a d a e s a i d a ∗ / i n = new BufferedReader ( new InputStreamReader ( socket . g e tIn p u tS tr e a m ( ) ) ) ; o u t = new P r i n t W r i t e r ( socket . getOutputStream ( ) , t r u e ) ; 30 31 32 33 34 35 36 while ( ( mensagemEnviar = inReader . r e a d L i n e ( ) ) ! = n u l l ) { 45 46 47 out . close ( ) ; i n . close ( ) ; socket . c l o s e ( ) ; / ∗ Envio da mensagem ∗ / o u t . p r i n t l n ( mensagemEnviar ) ; / ∗ Recebimento da r e s p o s ta do s e r v i d o r ∗ / S t r i n g r e s p o s ta = i n . r e a d L i n e ( ) ; 23 / 30 Multicast Utilizado com suporte da camada Ethernet Quando sem esse suporte, utiliza vários Unicast Conceito de grupo 24 / 30 Multicast usando a linguagem C Principais funções setsockopt (int s, int level, int optname, const void *optval, socklen t optlen); 25 / 30 Multicast em C – 1/3 Códigos retirados do arquivo MulticastReceiver.c 28 29 30 i f ( ( sock = socket ( PF INET , SOCK DGRAM, IPPROTO UDP ) ) < 0 ) { p r i n t f ( ” s o c k e t ( ) f a l h o u \n ” ) ; } 32 33 34 35 36 / ∗ c o n s t r u i r a e s t r u t u r a de endereco para o b i n d ∗ / memset (& m u l t i c a s t A d d r , 0 , s iz e o f ( m u l t i c a s t A d d r ) ) ; m u l t i c a s t A d d r . s i n f a m i l y = AF INET ; m u l t i c a s t A d d r . s i n a d d r . s a d d r = h t o n l ( INADDR ANY ) ; m u l t i c a s t A d d r . s i n p o r t = htons ( m u l t i c a s t P o r t ) ; 38 39 40 41 42 /∗ bind ∗/ i f ( bind ( sock , ( s t r u c t sockaddr ∗ ) & m u l t i c a s t A d d r , s iz e o f ( m u l t i c a s t A d d r ) ) < 0 ) { p r i n t f ( ” b i n d ( ) f a l h o u \n ” ) ; } 26 / 30 Multicast em C – 2/3 Códigos retirados do arquivo MulticastReceiver.c 44 45 46 47 48 49 50 51 52 / ∗ a c e r t a r opcoes do m u l t i c a s t ∗ / multicastRequest . i mr mul ti addr . s addr = inet addr ( multicastIP ) ; m u l t i c a s t R e q u e s t . i m r i n t e r f a c e . s a d d r = h t o n l ( INADDR ANY ) ; i f ( setsockopt ( sock , IPPROTO IP , IP ADD MEMBERSHIP , ( void ∗ ) & m u l ti c a s tR e q u e s t , s iz e o f ( m u l t i c a s t R e q u e s t ) ) < 0 ) { p r i n t f ( ” s e ts o c k o p t ( ) f a l h o u \n ” ) ; } 54 55 56 57 58 59 / ∗ Receive a s i n g l e datagram from th e s e r v e r ∗ / while ( 1 ) { i f ( ( r e c v S t r i n g L e n = r e c v fr o m ( sock , r e c v S t r i n g , MAXRECVSTRING, 0 , NULL , 0 ) ) < 0 ) { p r i n t f ( ” r e c v fr o m ( ) f a l h o u \n ” ) ; } 27 / 30 Multicast em C – 3/3 Códigos retirados do arquivo MulticastSender.c 30 31 32 i f ( ( sock = socket ( PF INET , SOCK DGRAM, IPPROTO UDP ) ) < 0 ) { p r i n t f ( ” s o c k e t ( ) f a l h o u \n ” ) ; } 39 40 41 42 memset ( & m u l t i c a s t A d d r , 0 , s iz e o f ( m u l t i c a s t A d d r ) ) ; m u l t i c a s t A d d r . s i n f a m i l y = AF INET ; multicastAddr . si n addr . s addr = i net addr ( mul ti castIP ) ; m u l t i c a s t A d d r . s i n p o r t = htons ( m u l t i c a s t P o r t ) ; 50 51 52 i n t k = sendto ( sock , s e n d S tr i n g , sendStringLen , 0 , ( s t r u c t sockaddr ∗ ) & m u l t i c a s t A d d r , s iz e o f ( m u l t i c a s t A d d r ) ) ; 28 / 30 Multicast usando a linguagem Java Principais classes MulticastSocket (int port) DatagramPacket (byte[] buf, int length) 29 / 30 Multicast em Java – 1/3 Códigos retirados do arquivo ServidorMulticast.java 11 MulticastSocket socket = new MulticastSocket ( p o r t a ) ; 12 13 In e tA d d r e s s endereco = In e tA d d r e s s . getByName ( args [ 1 ] ) ; socket . j o i n G r o u p ( endereco ) ; 15 16 17 18 19 20 while ( t r u e ) { b y te [ ] recvData = new b y te [ 1 0 2 4 ] ; DatagramPacket recvPacket ; recvPacket = new DatagramPacket ( recvData , recvData . l e n g t h ) ; socket . r e c e i v e ( recvPacket ) ; 23 24 25 26 sentence = new S t r i n g ( recvPacket . getData ( ) ) ; System . o u t . p r i n t ( recvPacket . getAddress ( ) . t o S t r i n g ( ) + ” : ” ) ; System . o u t . p r i n t l n ( sentence ) ; 30 / 30 Multicast em Java – 1/3 Códigos retirados do arquivo ClienteMulticast.java 13 MulticastSocket c l i e n t S o c k e t = new MulticastSocket ( ) ; 14 15 In e tA d d r e s s endereco = In e tA d d r e s s . getByName ( args [ 1 ] ) ; c l i e n t S o c k e t . j o i n G r o u p ( endereco ) ; 26 27 28 29 34 35 sendPacket = new DatagramPacket ( sendData , sendData . l e n g th , endereco , p o r t a ) ; c l i e n t S o c k e t . setTimeToLive ( t t l ) ; c l i e n t S o c k e t . send ( sendPacket ) ; c l i e n t S o c k e t . leaveGroup ( endereco ) ; cl i e n tSo cke t . close ( ) ; 31 / 30 Referências Man pages no Linux para funções C Especificação das classes Java na Internet 32 / 30