Python – Webserver em um minuto

PythonSimpleHTTP_www.cleitonbueno.com

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

Share Button

CC BY-NC-SA 4.0 Python – Webserver em um minuto by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.