Já ouviram a seguinte frase “A ocasião faz o ladrão”, não roubei nada, mas aproveitei a oportunidade para levar vantagens com o Python.
Estou eu entregando uma solução que desenvolvi para um cliente, eis que algo acontece e o webserver dele cai, não sei se Tomcat ou Jetty, era algum destes webservers Java, parou!
Não estou aqui para falar mau deles, além do mais, admiro muito o Tomcat por exemplo ele é webserver do ScadaBR, muito menos o Jetty que é o webserver ou foi por muito tempo do Zimbra Webmail e são fantásticos, porém, neste momento aconteceu o inesperado.
E ae o pior, precisava subir uma pagina com “Estamos em manutenção”, “Estamos atualizando nossos servidores”, “Estamos passando por instabilidade” algo assim para assustar menos os cliente, porém era um servidor Linux :), porém não tinha acesso direto a internet e apenas liberação da porta X ao firewall, e o desenvolvedor não conseguiu instalar um apache2, lighttpd e companhia limitada.
E nessa oportunidade, eu disse que poderia ajudar, subindo um webserver na porta 80 com Python até eles resolverem, não vou falar de ferramentas poderosas como Flask, Tornado, Twisted mas do simples SimpleHTTPServer, lembrava que era simples fazer, mas não lembrava como, então acessei docs do Python SimpleHTTPServer e vi o exemplo de configuração, que segue abaixo.
import SimpleHTTPServer import SocketServer PORT = 8201 Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer(("", PORT), Handler) print "servidor web na porta ", PORT httpd.serve_forever()
Pedi para o desenvolvedor criar um index.html com algum conteúdo e executei a aplicação no mesmo local do arquivo html.
user1@servidor:/home/pop/xwz $ python app.py
Você também por subir sem nenhum arquivo html, inserindo direto no código, com o seguinte exemplo.
import SimpleHTTPServer import SocketServer PORT = 8201 class my_handler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write("<center><h1>Servidor em manutencao!</h1></center>") return try: httpd = SocketServer.ThreadingTCPServer(('', PORT), my_handler) print "servidor web rodando na porta ", PORT httpd.serve_forever() except KeyboardInterrupt: print "Voce pressionou ^C, encerrando..." httpd.socket.close()
E indo mais além você pode executar a aplicação como usuário comum, e o diretório com os .html e .css em outro local, com o exemplo abaixo:
import SimpleHTTPServer import SocketServer PORT = 8201 class my_handler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): self.path = "/var/local/www/index.html" try: f_index = open(self.path) self.send_response(200) self.send_header('Content-type','text/html') self.end_headers() self.wfile.write(f_index.read()) f_index.close() except IOError: self.send_error(404, "Arquivo nao encontrado: %s" % self.path) return try: httpd = SocketServer.ThreadingTCPServer(('', PORT), my_handler) print "servidor web rodando na porta ", PORT httpd.serve_forever() except KeyboardInterrupt: print "Voce pressionou ^C, encerrando..." httpd.socket.close()
O segredinho esta no self.path especificando o local com o index.html.
Não sabia se atenderia a necessidade das I/O’s do site com o trafego, o cliente ficou feliz, no outro dia falei com ele e disse que funcionou muito bem até eles resolverem e voltarem o site no ar, agradeceu imensamente.
Uma curiosidade, segue um teste benchmark que executei com o ab do apache2-utils com o apache2 na porta 80 e nosso simples webserver com Python em uma VM.
Ambos execute com o seguinte comando:
$ ab -n 500 -c 50 http://127.0.0.1/ $ ab -n 500 -c 50 http://127.0.0.1:8201/
Apache2
Benchmarking 127.0.0.1 (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Finished 500 requests Server Software: Apache/2.2.16 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: / Document Length: 0 bytes Concurrency Level: 50 Time taken for tests: 1.262 seconds Complete requests: 500 Failed requests: 0 Write errors: 0 Non-2xx responses: 500 Total transferred: 122500 bytes HTML transferred: 0 bytes Requests per second: 396.10 [#/sec] (mean) Time per request: 126.230 [ms] (mean) Time per request: 2.525 [ms] (mean, across all concurrent requests) Transfer rate: 94.77 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 3.6 0 15 Processing: 16 119 23.4 123 159 Waiting: 9 116 22.9 121 148 Total: 21 121 20.8 123 159 Percentage of the requests served within a certain time (ms) 50% 123 66% 126 75% 129 80% 131 90% 137 95% 143 98% 148 99% 150 100% 159 (longest request)
SimpleHTTP(Python)
Server Software: SimpleHTTP/0.6 Server Hostname: 127.0.0.1 Server Port: 8201 Document Path: / Document Length: 49 bytes Concurrency Level: 50 Time taken for tests: 1.224 seconds Complete requests: 500 Failed requests: 0 Write errors: 0 Total transferred: 83500 bytes HTML transferred: 24500 bytes Requests per second: 408.38 [#/sec] (mean) Time per request: 122.435 [ms] (mean) Time per request: 2.449 [ms] (mean, across all concurrent requests) Transfer rate: 66.60 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.5 0 4 Processing: 2 14 76.5 9 1220 Waiting: 1 12 76.6 7 1219 Total: 2 15 76.7 10 1224 Percentage of the requests served within a certain time (ms) 50% 10 66% 10 75% 11 80% 11 90% 12 95% 13 98% 14 99% 15 100% 1224 (longest request)
Esse Python só surpreende heim!
Nessa eu ganhei crédito com o cliente, estou compartilhando um caso real e ajudando a alguém mais que precisar a solucionar de forma simples e pratica para subir um webserver, quer algo mais potente em Python o SimpleHTTPServer não atende? Pesquise por Twisted ou Flask e se surpreenda.
Referências
https://docs.python.org/2/library/simplehttpserver.html
https://docs.python.org/2/library/socketserver.html
http://httpd.apache.org/docs/2.2/programs/ab.html
Python – Webserver em um minuto by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.