acessando a internet com o python

18
Rede em Python Rede em Python Antonio Sérgio Nogueira Presidente Prudente 2009

Upload: antonio-sergio-nogueira

Post on 27-May-2015

7.996 views

Category:

Education


3 download

DESCRIPTION

Acessando a Ineternet com o Python, socket, protocolos etc...

TRANSCRIPT

Page 1: Acessando a Internet com o Python

Rede em Python

Rede em Python

Antonio Sérgio Nogueira

Presidente Prudente2009

Page 2: Acessando a Internet com o Python

Rede em Python

Rede em Python

1. A REDE – Existe uma palavra por trás de toda essa tecnologia que chegou ao mercado – a rede(network). Não importa se você está transferindo um arquivo ou navegando com seu browser favorito, toda esta tecnologia de rede está por trás disto, o Python tem um número grande de módulos para trabalhar com ela, que em baixo nível é acessada através de um conceito chamado socket. Neste tópico iremos falar sobre a comunicação entre programas na rede. Não é necessário dois computadores em rede para testar os programas, basta usarmos a rede para estabelecer a comunicação entre processos num mesmo computador.Quando falamos em rede encontramos alguns termos que mostraremos a seguir: Socket é o ponto de conexão da rede. Quando queremos nos conectar a uma rede através de um browser devemos criar um socket e instruí-lo a conectar ao computador servidor que também possue um socket que fica aguardando as requisições, um socket pode receber e enviar mensagens. Cada socket em uso é ligado a um número de IP e a um número de Porta.IP é uma sequência de 4 números na faixa de 0 a 255( 234.112.130.1), sequência que endereça o computador na rede. Existem números de IP que são reservados um deles é o IP “127.0.0.1” que é o localhost, ou seja o computador local, usado para fazer a conexão entre programas que estão rodando na mesma máquina. O uso do IP pode ser facilitado através dos DNS.DNS (Domain Name Servers) são computadores que fazem a conversão dos nomes em endereços da rede.Porta é um número de 0 a 65535, que serve para determinar uma conversação em particular, os números de 0 a 1023 são reservados para serviços de rede conhecidos( a porta 80 é usada pela WEB).Diferentes protocolos são usados na rede, um deles é o HTTP, usado para comunicar-se entre Browsers e Servidores Web, que é construído em cima do protocolo TCP, cuja construção gira em torno do protocolo IP.Protocolo – formato das mensagens e regras de conexão que atuam em cima dos sockets. Quando transmitimos dados entre dois programas podemos escolher entre o TCP e o UDP. O protocolo TCP cria uma conexão persistente entre os dois pontos o que garante o envio e recebimento correto e em ordem dos dados. Já o protocolo UDP não é orientado a conexão, mas é mais rápido e menos seguro, podendo os dados não chegar ou serem recebidos desordenadamente .

1.1 Níveis de Rede – a rede está dividida em 7 níveis ou camadas de acordo com o padrão OSI/ISO, o qual sugere os seguintes níveis:Físico – define as informações necessárias para transferir os dados sobre os componentes físicos, como os cabos.Data Link - define a forma como os dados são transferidos dos componente e para os componentes. Correção de erros ponto a ponto são definidos neste nível.Rede – organiza a rede assinalando endereços distintos para seus componentes, então a informação pode ser roteada para o computador certo. O protocolo IP trabalha nesta camada.Transporte – empacota os dados e faz os dados chegar ao destino sem erros. TCP e UDP são os protocolos que implementam essas responsabilidades.Sessão – Manipula cada conexão individual feita pelas máquinas.Apresentação – usada para sobrepor as diferenças como formatos de inteiros em diferentes plataformas, Python tem o módulo struct para fazer isto.Aplicação – implementa o produto final, sua aplicação. Cliente FTP, SMTP/POP3 manipulador de email e HTTP browser são exemplos de aplicações completas que rodam na rede.

2. Sockets – São objetos que fornecem um padrão portável para aplicações em redes e trabalham

Page 3: Acessando a Internet com o Python

Rede em Python

com certos protocolos de rede (TCP/IP, UDP/IP, etc..). Eles permitem que programas aceitem conexões para receber e enviar dados. Cada socket tem um tipo que define o protocolo que implementa o ambiente onde o socket é usado. Os três tipos mais populares são stream, datagram e raw. O tipo stream e datagram pode interfacear diretamente o protocolo TCP. Já o tipo raw é a interface do protocolo IP. O módulo socket é uma interface objeto base que permite acessar a rede tipo BSD no nível inferior. Ele fornece várias métodos e chamadas de erro para trabalhar com a rede de computadores.

socket(family, type [,protocol]) – este método cria e retorna um novo objeto socket. O valor de family pode ser AF_INET para a Protocolo IPv4 como o TCP e o UDP. O valor de type pode serstream para protocolo TCP(SOCK_STREAM) e datagram para protocolo UDP(SOCK_UDP).O terceiro argumento opcional só é usado com raw sockets(SOCK_RAW e family AF_INET).

gethostname() retorna o nome do computador na qual o programa está executando.

>>>import socket>>>socket.gethostname()'sssssssss'

gethostbyname(name) retorna o endereço IP, checando primeiro se o computador corrente pode fazer a conversão, se não for possível esta requisição é feita a um computador remoto DNS, se não for possível retorna erro.

>>>socket.gethostbyname('www.python.org')'132.151.1.90'

getservbyname(service, protocol) retorna o número da porta do serviço.

>>>socket.getservbyname('http','tcp')80

Número das Portas:80 - HTTP – Web pages119 – NNTP – Usenet news20/21 – FTP transfer/FTP control – Transferência de arquivos25 – SMTP – Envio de e-mail110 – POP3 – Busca de e-mail143 – IMAP4 – Busca de e-mail23 – TELNET – Linha de Comando70 – Gopher – Transferência de Documentos

accept() - aceita uma nova conexão e retorna os valores: o novo objeto socket e e o endereço do socket está comunicando.

bind(hostmane, port) – conecta o socket ao endereço da porta.

close() - fecha o socket.

connect(hostname, port) – conecta-se com outro socket, que pode ser externo ou local. Para

Page 4: Acessando a Internet com o Python

Rede em Python

conexão local use como hostname localhost.

getpeername() - retorna o endereço IP e a porta na qual o socket está conectado.

getsocketnome()- retorna o endereço IP da porta do próprio socket.

listen(max_connections) – inicia ouvindo a porta e fica esperando outras conexões. O sistema Operacional recusa novas conexões quando ela atingir o valor máximo de conexões.

makefile([modem [,buffersize]]) – cria um objeto arquivo para ler e escrever, útil em protocolos orientados a stream.

recvfrom(buffersize) – retorna uma string de dados do socket, usado para protocolo UDP.

send(string) – envia uma string de dados pelo socket. Usada em protocolo UDP.

sendto(string,(hostname,port)) – envia string para o servidor hostname na porta port.

setblocking(flag) – bloqueia todas as leituras e escritas no socket

3. Trabalhando com sockets – para programar sockets temos as portas padrões definidas anteriormente, de tal forma que programas como browsers saibam de antemão em qual porta se comunicar. Desta forma temos na NET uma estrutura cliente/servidor, de um lado máquinas que ficam rodando programas para atender requisitos de conexão(servidores) e do outro lado máquinas que utilizam estes serviços (clientes). O servidor é uma máquina que executa um programa ( normalmente um servidor web) que fica ouvindo a porta 80 tratando as requisições através de processos threads ou forks. Já o Cliente é uma máquina, que executa um programa, que quer falar com um servidor específico que tem um nome e usa a porta 80 para comunicação(browser). Na NET temos alguns clientes como o Internet Explorer, o Firefox, etc... Geralmente vários clientes podem se conectar através de um socket, e funcionalmente protocolos que rodam em cima deles fazem uma tarefa bastante familiar como: navegar na Internet, ler e-mail, postar mensagens em grupos, fazer downloads, etc...Os protocolos são mensagens estruturadas que atuam em cima dos sockets e tornam as comunicações mais robustas, evitando travamentos, estabelecendo conexões persistentes, etc... O TCP/IP o mais usado na internet, foi criado pelo Departamento de Defesa do EUA. A parte IP do protocolo cuida do roteamento dos pacotes enviando eles através da rede. Já o TCP cuida da principal forma de comunicação sobre a Internet fornecendo uma confiável distribuição de pacotesa na sequência. Já o protocolo UDP (USER DATAGRAM PRTOCOL), é outro protocolo que prove uma conexão não confiável mas bastante rápida, ele é útil para fluxo de mídia (streaming media), onde atrasos e repetições não são desejáveis.Em Python temos vários módulos que trabalham com protocolos diferentes, eles são nomeados normalmente da seguinte forma: XXXlib.py onde XXX é o nome do protocolo. Vejamos alguns módulos:

httplib,ftplib,nntplib protocolos HTTP, FTP e NNTPpoplib,imaplib,smtlib protocolos POP, IMAP e SMTP (e-mail)socket comunicação via internetcgi módulo que suporta script CGI no lado servidor

Page 5: Acessando a Internet com o Python

Rede em Python

urllib busca páginas web

4.Programação com SOCKET – como já falamos anteriormente temos dois tipos de programas: um que recebe as requisições (servidor) e outro que pede as informações (cliente). Para criarmos a conexão entre máquinas, devemos importar o módulo socket, criar o objeto socket, e chamar os métodos do objeto para enviar e receber as comunicações.

Programa Servidor: socketserver.pyfrom socket import * # importamos o módulo socketmyhost='' #definimos o endereço do host(servidor) - '' - localhostmyport=50006 #definimos a porta de comunicação

sockobj=socket(AF_INET,SOCK_STREAM) #criamos o objeto socket TCPsockobj.bind((myhost, myport)) #conectamos ao servidor o número da portasockobj.listen(5) #ouvimos a conexão, permitimos até 5 conexões

while True: #ouvimos a porta até o processo encerrar connection, address=sockobj.accept() #esperamos a próxima conexão do cliente print 'Servidor Conectado por', address #sinalizamos uma nova conexão while True: data=connection.recv(1024) #recebemos os dados print data #imprimimos os dados if not data: break #término da recepção connection.send("Echo=>"+data) #retornamos o dado ao cliente connection.close() #fechamos a comunicação

Programa Cliente:socketclient.pyimport sys #importa módulo funções do sistemafrom socket import * #importa módulo socketserverhost='localhost' #define o servidor, se o servidor estiver em outra

#máquina basta colocar o IP da máquinaserverport=50006 #porta de conexão

message=['Ola Mundo'] #mensagem a ser enviada ao servidorif len(sys.argv)>1: #define o nome do servidor como 1o. argumento do serverhost=sys.argv[1] #script if len(sys.argv)>2: #uma mensagem para cada argumento,2o. em diante message=sys.argv[2:]sockobj=socket(AF_INET,SOCK_STREAM) #gera o objeto socketsockobj.connect((serverhost,serverport)) #conecta-se ao servidor

for line in message: sockobj.send(line) #envia mensagem data=sockobj.recv(1024) #recebe retorno da mensagem print 'Cliente Recebeu:',repr(data) #imprime mensagem

sockobj.close() #fecha conexão

Page 6: Acessando a Internet com o Python

Rede em Python

Detalhando as instruções dos programas anteriores:

sockobj=socket(AF_INET, SOCK_STREAM) – cria um socket TCP/IP padrão da internet, AF_INET define como protocolo de endereçamento o IP e SOCK_STREAM define como protocolo de transferência o protocolo TCP.

sockobj.bind((myhost,myport)) – associa ao objeto socket o endereço IP e o número da porta na qual estabeleceremos a comunicação. No lado servidor o nome pode ser em branco para definir que o servidor roda na máquina local, já no lado do cliente devemos definir o endereço IP, que pode ser localhost quando cliente e servidor estão na mesma máquina.

sockobj.listen(5) – inicia a monitoração da comunicação, definindo o número de requisições que o servidor suporta na sua lista de espera. O número 5 é mais que suficiente para receber as comunicações, uma vez que cada requisição chega ao servidor ela é tratada e retirada da fila.

Loop servidor - o servidor entra num loop aguardando a comunicação através do comando connection, address=sockobj.accept(), uma vez ela estabelecida um novo objeto é criado para conexão(connection) e os dados então podem ser recebidos através do comando data=connection.recv(1024) e transmitidos através do comando connection.send("Echo=>"+data).Cliente – no lado do cliente temos a transmissão da mensagem através da função send e a recepção através da função recv, do objeto sockobj.

connection.close() fecha a conexão do servidor e sockobj.close() encerra a conexão do cliente.

Outro exemplo simples:# TCP clienteimport socketclisocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)clisocket.connect(("localhost", 8888))clisocket.send('comuniquei')data = clisocket.recv(1024)clisocket.close()print "Recebi o dado: ", data

# TCP servidorimport socketsvrsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)svrsocket.bind(("", 8888))svrsocket.listen(5)while 1: data_to_send = "Dados do servidor" data_received='' clisocket, address = svrsocket.accept() print "endereco: ", address

Page 7: Acessando a Internet com o Python

Rede em Python

data_received=clisocket.recv(1024) print data_received clisocket.send(data_to_send) clisocket.close()

5. Conexão com vários clientes simultâneos – quando vários clientes se conectam ao servidor se o tempo de resposta for longo a conexão falha. Para resolver este problema a melhor solução é usar um processamento paralelo através de threads, multiplexagem ou forks. O processo forks é similar ao processo de threads e é disponível apenas em sistemas Linux, por isso não abordaremos aqui. O único cuidado que devemos tomar com processos forks é que eles devem ser encerrados para que não fiquem executando no sistema como processos Zumbi.5.1 Threads – as threads rodam paralelamente e compartilham a memória global e na maioria das vezes são mais eficientes que as forks e trabalham bem mas plataformas Unix e Windows e ao encerrar não deixam processos zumbis rodando.

from socket import * # importa módulo socketimport thread,time #importa módulo threadmyhost='' #define nome do host como localmyport=50008 #define a porta

sockobj=socket(AF_INET,SOCK_STREAM)sockobj.bind((myhost, myport))sockobj.listen(5)

def tratamentocliente(connection): time.sleep(5) while True: data=connection.recv(1024) print data if not data: break connection.send("Echo=>"+data) connection.close() while True: connection, address=sockobj.accept() #abre a conexão gerando um objeto connection print 'Servidor Conectado', address thread.start_new(tratamentocliente,(connection,)) # inicia um processo para tratar essa conexão

Para testar este servidor e ver ele executando paralelamente abra duas ou mais janelas do DOS e execute o programa cliente. O programa é executado paralelamente deixando os processos na fila por 5s.

5.2 Usando a biblioteca SocketServer – é uma biblioteca que facilita escrever programas servidores com threads ou forks.

import SocketServer, timemyhost=''myport=50008def now():

Page 8: Acessando a Internet com o Python

Rede em Python

return time.ctime(time.time())

class MyClientHandler(SocketServer.BaseRequestHandler): def handle(self): print self.client_address,now() time.sleep(5) while True: data=self.request.recv(1024) if not data: break self.request.send('Echo %s em %s' %(data,now())) self.request.close()

myaddr=(myhost,myport)server=SocketServer.ThreadingTCPServer(myaddr,MyClientHandler)server.serve_forever()

Estamos usando o módulo SocketServer neste exemplo, e para mudar de thread para fork basta substituir a classe para ForkingTCPServer.

5.3 Multiplexagem – para executar os programas paralelamente o sistema operacional na realidade particiona cada tarefa e executa um pedaço de cada, simulando que está executando elas ao mesmo tempo. Na realidade a execução paralela só ocorre em máquinas que tenham mais de uma CPU. Em python ainda podemos fazer este tipo de paralelismo executado pela forks ou pela thread usando a biblioteca select, que verifica qual socket está pronto para transmitir e então dá atenção a esta parte do programa. A função select é de longe o mecanismo mais simples. Esta função tem (de fato), quatro argumentos: três "listas" de sockets, e um tempo limite. As três listas socket indicam o interesse em ler, escrever e eventos de exceção para cada soquete listado. A função irá retornar sempre que um desses eventos é acionado. Se nada acontecer dentro do tempo limite, a função simplesmente retorna. O resultado da função select () é de três listas que lhe diz que soquete que disparou eventos. Sua aplicação terá uma rotina de tratamento para cada tipo de evento esperado. Esse manipulador irá realizar tarefas diferentes, dependendo da sua aplicação. Se uma ligação tem uma necessidade de manter informações de estado, você provavelmente vai acabar escrevendo uma máquina do Estado para lidar com as transições entre diferentes comportamentos. Desta forma um ciclo de eventos simples será suficiente que é acoplado a um laço que limita este tempo em segundos(sugestão 30s).

#servidor com selectimport sys,timefrom select import selectfrom socket import socket,AF_INET,SOCK_STREAM

def now(): return time.ctime()

myhost=''myport=50007if len(sys.argv)==3: myshost,myport=sys.argv[:1]

mainsocks,readsocks,writesocks=[],[],[]

Page 9: Acessando a Internet com o Python

Rede em Python

portsock=socket(AF_INET,SOCK_STREAM)portsock.bind((myhost,myport))portsock.listen(5)mainsocks.append(portsock)readsocks.append(portsock)

while True: readables,writeables,exceptions=select(readsocks,writesocks,[]) for sockobj in readables: if sockobj in mainsocks: newsock,address=sockobj.accept() print 'Conectado',address,id(newsock) readsocks.append(newsock) else: data=sockobj.recv(1024) if not data: sockobj.close() readsocks.remove(sockobj) else: sockobj.send(data)

Outro exemplo:import selectimport socketApp_Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)App_Socket.bind("", 50008)App_Socket.listen(5)while 1: readable_sockets = [App_Socket] writable_sockets = [] r, w, err = select.select(readable_sockets, writable_sockets, [], 0) if r: client, address = service.accept() client.send("data") client.close()

O select permite que as chamadas ao socket como accept ou recv não bloqueie o programa. Maiores detalhes consultar biblioteca. Atenção: existe um método em socket chamado setblocking capaz de posicionar os comandos para bloquear ou não o comando (bloquear significa deixar o comando aguardando a recepção de um dado). Existe um sistema chamado TWISTED que implementa estas rotinas de servidor assíncrono de uma forma eficaz (TWISTED – servidor de rede dirigido a eventos e distribuído sob licença do MIT).

6. Protocolo UDP – para troca de pequenas mensagens entre máquinas sem a necessidade de confiabilidade, podemos usar o protocolo UDP, neste protocolo se a mensagem não chegar ao destino ela é descartada.

Programa servidor: serverudp.py

Page 10: Acessando a Internet com o Python

Rede em Python

# servidor UDP - serverudp.pyimport socketport = 50007s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# Aceita datagramas UDP na porta dada, enviado por qualquer clientes.bind(("", port))print "Esperando DADOS na porta:", portwhile True: # Recebe até 1024 bytes no datagrama data, addr = s.recvfrom(1024) print "Recebido:", data, "de:", addr

Programa cliente: clientudp.py# cliente UDP - clientUDP

import socketport = 50007host = "localhost"s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.sendto("Olá servidor. Estou no ar.", (host, port))O método bind não é usado nesta comunicação.Utilize estas linhas de programa para enviar grandes mensagens:

BUFSIZE = 1024while msg: bytes_sent = s.sendto(msg[:BUFSIZE], (host, port)) msg = msg[bytes_sent:]

7. Protocolo SNTP -este protocolo de comunicação SIMPLE NETWORK TIME PROTOCOL é um protocolo de sincronização dos computadores da rede(NTP). Na Internet temos servidores de horário de dois níveis, ou camadas, de servidores de horário NTP (Network Time Protocol) disponíveis na Internet. Definido pelo RFC (Request for Comments) 1305.Os de primeiro nível destinam-se basicamente a agir como servidores de horário de origem para os servidores de horário do segundo nível. Os servidores de horário de primeiro nível também podem ser capazes de fornecer serviços de tempo essenciais para a missão. Alguns servidores de horário de primeiro nível acesso restrito. Os servidores de horário de segundo nível destinam-se às necessidades gerais de serviço de tempo SNTP. Os servidores de horário de segundo nível geralmente permitem o acesso público. É recomendado que você utilize servidores de horário de segundo nível para uma configuração normal do servidor de horário SNTP, pois eles normalmente estão localizados em uma rede mais próxima que pode produzir atualizações mais rápidas e mais precisas(veja: Microsoft Ajuda e Suporte). O NTP utiliza a porta 123, de modo que essa porta seja aberta em um firewall ou um roteador para garantir a comunicação adequada com o servidor NTP.No Brasil acesse o servidor de horário de 2o. Nível: Brazilian Research Network200.144.121.33:ntp.cais.rnp.br #gettimeserverSNTP.py

Page 11: Acessando a Internet com o Python

Rede em Python

import socket, struct, sys, timeTIME1970 = 2208988800Lclient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)data = '\x1b' + 47 * '\0'client.sendto(data, (sys.argv[1], 123))data, address = client.recvfrom(1024)if data: print 'Resposta recebida de:', address t = struct.unpack('!12I', data)[10] t -= TIME1970 print '\tTime=%s' % time.ctime(t)

Para executar este programa digite numa janela do DOS: python gettimeserverSNTP.py ntp.cais.rnp.br

Um SNTP começa com o cliente enviando um datagrama UDP de 48 bytes que começa com o byte '\x1b', seguido por nulos. O servidor responde com um datagrama de 48 bytes ou 12 palavras de 4 bytes. 11 destes bytes são o número de segundos passados até hoje, basta então subtrair o número de segundos até 1970(no python a data inicial de contagem de segundos começa a partir de 1970) e pronto basta usar a função ctime do módulo time e temos a data e hora do sistema.

8. Acessando URL – se você quiser pegar um documento de uma URL na WEB, o Python fornece os módulos urllib e urlparse ferramentas para processar URL( Uniform Resource Locator). O módulo urllib é uma interface para recuperar dados através da WEB, e suporta protocolos HTTP, FTP e conexões gopher usando sockets.

Veja este exemplo que retorna uma página da WEB:from urllib import urlopendoc = urlopen("http://www.python.org").read( )print doc

Ou este exemplo:import urllibpage=urllib.urlopen(“http://www.python.org”).read()page.readline()

teste também, no lugar de page.readline() :

for key,value in page.headers.items(): print key,”=”,value

Copiando uma página da WEB para um arquivo: #urlcopiasite.pyimport urllibpagehandler = urllib.urlopen("http://www.python.org")outputfile = open("site.html", "wb")while 1: data = pagehandler.read(512) if not data: break

Page 12: Acessando a Internet com o Python

Rede em Python

outputfile.write(data)outputfile.close()pagehandler.close()

9. HTTP – é um protocolo simples baseado em texto e usado em aplicações WEB. Ambos servidor e browser WEB implementam este protocolo. Para trabalhar com este protocolo o browser deve abrir a conexão e enviar um cabeçalho de requisição para o servidor WEB. Esta requisição é um simples formulário de texto que contém os métodos requisitados(GET, POST, PUT...), o nome do arquivo que será aberto, etc... O servidor interpreta a requisição e retorna a resposta ao cliente. Esta resposta contém o número de versão do HTTP, e informações como cookies, tipo e tamanho do documento que será enviado (http://www.w3.org/Protocols).Para construir WEB Servers você pode usar os seguintes módulos:

– SocketServer – é um socket base para servidor IP.– BaseHTTPServer – Infraestrutura para os próximos dois módulos.– SimpleHTTPServer – Permite desenvolver um servidor WEB simples.– CGIHTTPServer – Permite a implementação de servidor HTTP com CGI

O módulo SocketServer possui ferramentas de trabalho que simplificam a tarefa de escrever servidores de rede. Ao invés de ter que implementar servidores usando um socket(módulo de baixo nível), este módulo fornece quatro classes de servidor de base que implementam as interfaces com os protocolos utilizados na maioria das vezes: TCPServer, UDPServer, StreamRequestHandler e DatagramRequestHandler. Todas essas classes processam requisições sincronamente. Cada requisição deve ser completada antes que novas requisições possam ser iniciadas, o que não é aceitável quando existem tarefas muito longas, o que deixaria o processo lento. Então elas podem ser tratadas em threads separadas, usando as classes: ThreadingTCPServer, ThreadingUDPServer, ForkingUDPServer e ForkingTCPServer. (Citado acima no item 5.2)O módulo BaseHTTPServer define duas classes base para implementar servidor HTTP(WEB Server). É construído em cima do módulo SockerServer e raramente é usado diretamente. Vamos mostrar em seguida um Servidor HTTP usando a classe BaseHTTPRequestHandler.

Programar servidor com BaseHTTPServer:import BaseHTTPServerhtmlpage = """<html><head><title>Web Page</title></head><body>Alo Mundo Python</body></html>"""notfound = "Arquivo nao encontrado"class WelcomeHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): if self.path == "/": self.send_response(200) self.send_header("Content-type","text/html") self.end_headers() self.wfile.write(htmlpage) else: self.send_error(404, notfound)httpserver = BaseHTTPServer.HTTPServer(("",80), WelcomeHandler)httpserver.serve_forever()

Page 13: Acessando a Internet com o Python

Rede em Python

Para executar este servidor HTTP basta entrar no seu browser e digitar: //http:localhost/ , se quiser obter o erro digite: //http:localhost// .

10. FTP – o protocolo FTP(File Transfer Protocol) é a forma mais popular de transferir dados ente máquinas através da rede. Ele pode trabalhar permitindo apenas que usuários cadastrados transfiram dados ou que qualquer um transfira os dados. Para implementar este tipo de cliente usamos o módulo FTP ftplib. Esta implementação FTP utiliza duas portas uma de controle e outra de transferência de dados, evitando assim problemas de travamento.

#ftpsimples.pyimport ftplibftp = ftplib.FTP('ftp.puc-rio.br')ftp.login()ftp.cwd('pub/puc/ftp')ftp.retrlines('LIST') #visualiza diretorio de arquivosfile = open('puc.txt', 'w')ftp.retrbinary('RETR Estatistica-FTP-Arquivo-Semanal.txt', file.write, 2000)ftp.quit()

Para fazer um Upload:

import ftplibftp = ftblib.FTP(“ftp.puc-rio.br”)ftp.login("username", "password")filename = "index.html"ftp.storlines("STOR " + filename, open(filename))filename = "app.exe "ftp.storbinary("STOR " + filename, open(filename, "rb"), 1024)

11. SMTP/POP3/IMAP – quando falamos nestes protocolos estamos falando em protocolos usados na internet para trabalhar com emails (SMTP e POP3). O SMTP(Simple Mail Transfer Protocol) é usado oficialmente para transferir emails pela Internet (coloca os emails nas caixas de email dos servidores de email) e o protocolo POP(Post Office Protocol) é usado para permitir acessar remotamente a caixa de email lendo e escrevendo email dos servidores de email. O IMAP(Internet Message Acess Protocol) é outro protocolo que está sendo usado para leitura de emails, ou seja acessa o email em um servidor remoto como se ele fosse local.

Python fornece um sofisticado conjunto de classes para construção de mensagens de e-mail. Geralmente podemos dizer que um e-mail é uma string com um formato pré-definido. Tudo que você necessita para enviar um e-mail é uma string formatada, um endereço mail to e o módulo smtplib. Veja exemplo:

>>> import smtplib>>> server=smtplib.SMTP('gmail-smtp-in.l.google.com',25)>>> para='[email protected]'>>> de='[email protected]'>>> msg='''From:[email protected]

Page 14: Acessando a Internet com o Python

Rede em Python

To:[email protected]: Nao tenho nada pra dizer.Aqui eh a mensagem.'''>>> server.sendmail(de,para,msg){}>>> server.close()

A classe SMTP do módulo smtplib serve para se conectar com um servidor de e-mails, caso você tenha um servidor de e-mail local, basta usar 'localhost'. E 25 é a porta padrão do SMTP.

Um e-mail consiste de um conjunto de cabeçalhos e um corpo( a mensagem). Os cabeçalhos são enviados geralmente como um par de valores separados por ':' e um espaço (exemplo: 'Subject: OI')Você pode criar uma mensagem conforme o padrão RFC2822 usando o Python através da classe message. O objeto Message atua como um dicionário mapeando a mensagem cabeçalho e valor, e também tem o corpo do texto que é o payload. >>> from email.Message import Message>>> message=Message()>>> message['Subject']='Ola'>>> message.set_payload('Corpo da mensagem')>>> print str(message)From nobody Tue Sep 08 14:44:32 2009Subject: Ola

Corpo da mensagem>>>

A seguir mostramos alguns cabeçalhos padrão da mensagem definida pela norma RFC2822:

Cabeçalho Exemplo Propósito

To To: Sergio<[email protected]> Endereço da pessoa que receberá a mensagem

From From: Jose<[email protected]> Endereço da pessoa que enviou o email.

Date Date:Sun, 16 Jan 2009 14:56:32 A data que a mensagem foi enviada.

Subject Subject: Ola O título ou o sumário da mensagem.

Cc Cc:[email protected], Jose<[email protected]>

Endereço de pessoas que devem receber a mensagem, mesmo que não são endereçadas para elas.

Corpo da mensagem Mensagem com até 1000 caracteres* S ó p o d e m o s u s a r o s p r i m e i r o s 1 2 7 c a r a c t e r e s A S C I I .

Para enviar mensagems com outros caracteres e com gráficos e arquivos binários usamos a extensão do RFC2822 chamada de MIME(Multipurpose Internet Mail Extension), padronizado através da norma RFC 1521. A parte mais importante do MIME são as codificações, que fornecem uma forma

Page 15: Acessando a Internet com o Python

Rede em Python

de codificar 8bits em 7bits, duas codificações são definidas pelo MIME a codificação Base64 e a codificação quoted-printable.

>>> from email.MIMEImage import MIMEImage>>> filename = 'inverno.jpg'>>> msg = MIMEImage(open(filename).read(),name=filename)>>> msg['To']='[email protected]'>>> msg['From']='[email protected]'>>> msg['Subject']='Foto'>>> print str(msg)From nobody Wed Sep 09 14:28:44 2009Content-Type: image/jpeg; name="inverno.jpg"MIME-Version: 1.0Content-Transfer-Encoding: base64To: [email protected]: [email protected]: Foto

/9j/4AAQSkZJRgABAgEAYABgAAD/7RBKUGhvdG9zaG9wIDMuMAA4QklNA+0KUmVzb2x1dGlvbgAAAAAQAGAAAAABAAEAYAAAAAEAAThCSU0EDRhGWCBHbG9iYWwgTGlnaHRpbmcgQW5nbGUAAAAABAAAAHg4QklNBBkSRlggR2xvYmFsIEFsdGl0dWRlAAAAAAQAAAAeOEJJTQPzC1ByaW50IEZsYWdzAAAACQAAAAAAAAAAAQA4QklNBAoOQ29weXJpZ2h0IEZsYWcAAAAAAQAAOEJJTScQFEphcGFuZXNlIFByaW50IEZsYWdzAAAAAAoAAQAAAAAAAAACOEJJTQP1F0NvbG9yIEhhbGZ0b25lIFNldHRpbmdzAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+BdDb2xvciBUcmFuc2ZlciBTZXR0aW5ncwAAAHAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQIBkd1aWRlcwAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHg1VUkwgb3ZlcnJpZGVzAAAABAAAAAA4QklNBA==

>>> server=smtplib.SMTP('gmail-smtp-in.l.google.com',25)>>> server.sendmail('[email protected]','[email protected]',str(msg)){}>>> server.close()>>>

Veja no exemplo acima como ficou a mensagem codificada através da função MIME e depois observe que enviamos ela pela rede e fechamos a conexão. Quando temos um email com múltiplos arquivos podemos usar a classe email.MimeMultipart em conjunção com as outras classes email.Mime*.

Page 16: Acessando a Internet com o Python

Rede em Python

Protocolo POP3 – como normalmente o servidor de email localiza-se numa máquina da rede, para buscar um email do servidor de email você precisa de um protocolo, no caso o POP3(Post Office Protocol revisão 3) que está em declínio de popularidade. O protocolo foi definido pela norma RFC1725. O módulo poplib implementa clientes POP3, a referência desta biblioteca descreve o protocolo como obsoleto, e recomenda o uso do IMAP4 se o servidor aceitar.

>>> m=poplib.POP3_SSL('pop.gmail.com')>>> m.user('asergionogueira')'+OK send PASS'>>> m.pass_(getpass.getpass())Warning: Problem with getpass. Passwords may be echoed.Password: suasenha'+OK Welcome.'>>> nummessages=len(m.list()[1])>>> print nummessages635>>> print m.retr(2)[1] # um valor entre 1 e 635['Received: by 10.86.33.4 with HTTP; Wed, 11 Jun 2008 19:18:24 -0700 (PDT)', 'Message-ID: <[email protected]>', 'Date: Wed........…..........................….........................-=_Part_24989_12520194.1213237104237--']

Protocolo IMAP4 - O outro protocolo para acessar um caixa de correio em um servidor remoto é o IMAP, o Internet Message Access Protocol. A mais recente revisão do IMAP é definido no RFC 3501, e tem características muito mais de POP3. É também a ganhar popularidade em mais de POP3. A principal diferença entre POP3 e IMAP é que o POP3 é projetado para agir como uma caixa de correio e só detém seu e-mail por um tempo até você coletá-lo. IMAP é projetada para manter seu e-mail permanentemente armazenados no servidor. Entre outras coisas, você pode criar pastas no servidor, para diferentes email, e buscá-los. Com o IMAP, umcliente de email só precisa expor esses recursos do IMAP, mas não é necessário implementá-las por conta própria. Mantendo o seu email no servidor faz com que seja mais fácil manter a configuração de email, mesmo enquanto se move a partir do computador para computador. Claro, você ainda pode baixar o correio para o seu computador e depois apagá-lo da servidor, como acontece com POP3. O IMAP4 é implementado através do módulo imaplib e está detalhado em RFC-1730 e RFC-2060. Iremos aqui mostrar apenas como recuperar mensagens.

>>> import getpass,imaplib>>> m=imaplib.IMAP4_SSL('imap.gmail.com',993)>>> m.login('[email protected]','suasenha')('OK', ['[email protected] authenticated (Success)'])>>> status,count=m.select('INBOX')>>> print status,countOK ['650']>>> status,data=m.search(None,'ALL')>>> print data['1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

Page 17: Acessando a Internet com o Python

Rede em Python

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 ….............7 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650']>>> status,data=m.fetch(650,'(RFC822)') #escolhi o de numero 650>>>print data[0][1]Delivered-To: [email protected]: by 10.101.69.8 with SMTP id w8cs414785ank; Thu, 10 Sep 2009 08:13:30 -0700 (PDT)Received: by 10.141.33.21 with SMTP id l21mr510299rvj.88.1252595610052; Thu, 10 Sep 2009 08:13:30 -0700 (PDT)Return-Path: <[email protected]>Received: from sharedrelay01.alog.com.br (sharedrelay.alog.com.br [200.155.24.164]) by mx.google.com with ESMTP id 5si3842282ywh.6.2009.09.10.08.13.29; Thu, 10 Sep 2009 08:13:29 -0700 (PDT)Received.................................…............................................YnNwOzwvUD48L1REPjwvVFI+PC9UQk9EWT48L1RBQkxFPg==>>> m.close()('OK', ['Returned to authenticated state. (Success)'])>>> m.logout()('BYE', ['LOGOUT Requested'])>>>

12. Protocolo NNTP – a biblioteca nntplib do Python implementa o lado cliente do protocolo NNTP. O protoco NNTP ou Network News Transfer Protocol é um protocolo da Internet para grupos de discussão da chamada usenet. Foi definido inicialmente pela RFC-977; vide também RFC-3977. Especifica o modo de distribuição, busca, recuperação e postagem de artigos usando um sistema de transmissão confiável. Para clientes de leitura de notícias, o NNTP habilita a recuperação de artigos armazenados em um banco de dados centralizado, permitindo aos assinantes a opção de selecionar somente os artigos nos quais estão interessados. Em seguida um exemplo:

>>> import nntplib>>> s=nntplib.NNTP('freenews.netfront.net')>>> resp,count,first,last,name=s.group('1.test')>>> print 'grupo',name,'tem',count, 'artigos de',first,'ate',lastgrupo 1.test tem 188 artigos de 112 ate 304>>> resp,subs=s.xhdr('subject',first+'-'+last)>>> print resp221 subject matches follow (NOV)>>> print subs[('113', 'der test [0/1] - Post Description (1/1)'), ('114', 'ATEST'), ('115', 'test'), ('116', 'etse'), ('117', 'TEST POSTING'), ('118', 'Please take a look at this and be your hone boss its totally Free'), ('119', 's'), ('120', 'd'), ('121', 'test'), ('122', '1test22'), ('123', 'RIZLA+ CIGARETTE ROLLING PAPERS & MORE'), ('124', 'RIZLA+ CIGARETTE ROLLING PAPERS & MORE'), ('125', 'test0201'), ('126', 'Test - do no...................…........................................ar'), ('304', 'bau bau')]

Page 18: Acessando a Internet com o Python

Rede em Python

>>> for id, sub in subs:print id, sub

113 der test [0/1] - Post Description (1/1)114 ATEST115 test116 etse117 TEST POSTING118 Please take a look at this and be your hone boss its totally Free119 s.........….............302 test303 zomaar304 bau bau>>>s.quit()

13. Protocolo Telnet – é um terminal de emulação de terminal para redes TCP/IP. O Telnet conecta seu computador a um servidor remoto, permitindo você enviar comandos através dele para o computador remoto. O módulo telnetlib fornece uma classe telnet que implementa o protocolo Telnet, veja RFC854. Veja exemplo a seguir.

import getpassimport sysimport telnetlib

HOST = "rt.njabl.org"user = raw_input("Enter your remote account: ")password = getpass.getpass()

tn = telnetlib.Telnet(HOST,2501)

tn.read_until("login: ")tn.write(user + "\n")if password: tn.read_until("Password: ") tn.write(password + "\n")

tn.write("ls\n")tn.write("exit\n")

print tn.read_all()

Referência Bibliográfica:

Python Cookbook – O'Relly

www.python.org