设为首页 收藏本站
查看: 747|回复: 0

[经验分享] python搭建简单的web服务器

[复制链接]

尚未签到

发表于 2015-12-2 08:56:40 | 显示全部楼层 |阅读模式
  由于要做自动化和性能测试,工作中需要有一个能够控制返回消息数据的web服务器,所以用python初步实现了一个简单的web服务器,能够处理HTTP的请求(GET,POST,PUT),并完成响应。
先简单说明下原理,python中实现web服务器大概分两个步骤:
  1.      创建一个套接字,绑定到指定的IP和端口,保持监听
  2.      创建一个handle类,当收到请求消息时,作出响应
  主要使用的类有两个:
  HTTPServer:HTTP服务器的基类,提供了HTTP服务器的常用方法,创建服务器时可以直接声明这个类,也可以根据需要从这个类继承。
  CGIHTTPRequestHandler:处理请求的handle类,继承自BaseHTTPRequestHandler类,在python文档中说明该类可以处理GET和POST请求,自己试了一下发现也可以处理PUT请求。
  有关这两个类的详细描述可以参考python的标准类库说明:https://docs.python.org/2/library/
  源码如下:
import socket
from os import curdir,sep
  from BaseHTTPServer import HTTPServer
  from CGIHTTPServer import CGIHTTPRequestHandler
  import json
class HttpHandler(CGIHTTPRequestHandler):
  def do_GET(self):
  try:
  f = open(curdir + sep + self.path)
  print self.path
  print 'This is a GET method!'
  self.send_response(200)
  self.send_header('Content-type',
  'text/html')
  self.end_headers()
  self.wfile.write(f.read())
  f.close()
  except IOError:
  self.send_error(404,'File Not Found:%s' % self.path)
  def do_POST(self):
  try:
  print self.path
  print 'This is a POST method!'
  self.data = self.request.recv(1024).strip()
  self.data =  json.loads(self.data)
  print self.data                        
  sendData = {}
  if self.path == '/getfile':
  f = open(curdir + sep + '/test_body.txt')
  fileContent = f.read()
  sendData['content'] = fileContent
  f.close()
  self.send_response(200)
  self.send_header('Content-type',
  'text/html')
  self.end_headers()
  self.wfile.write(sendData)
  except:
  self.send_error(404,'Invalid request:%s!' % self.path)
  def do_PUT(self):
  try:
  print self.path
  print 'This is a PUT method!'
  self.data = self.request.recv(1024).strip()
  print self.data
  sendData = {}
  if self.path == '/getfile':
  f = open(curdir + sep + '/test_body.txt')
  fileContent = f.read()
  sendData['content'] = fileContent
  f.close()
  self.send_response(200)
  self.send_header('Content-type',
  'text/html')
  self.end_headers()
  self.wfile.write(sendData)
  except:
  self.send_error(404,'Invalid request:%s!' % self.path)
  
  def main():
  try:
  localIp = socket.gethostbyname(socket.gethostname())
        server_address = (localIp,8080)
  http_server = HTTPServer(server_address,HttpHandler)
  sa = http_server.socket.getsockname()
  print "Serving HTTP on", sa[0], "port", sa[1], "..."
  print 'Press ^C once or twice to quit.'
  http_server.serve_forever()
  except KeyboardInterrupt:
  print '^C received,shutting down server.'
  http_server.socket.close()
  
  if __name__ == '__main__':
  main()      
  在main()函数中新建了一个HTTPServer类,绑定到本机的8080端口,并保持监听。当收到请求时,根据请求的方法类型进入不同的do_*函数。函数的处理逻辑很简单,如果发送的URL合法,设置返回码为200,然后读取一个文件的内容,并写入到返回消息中。这样一个简单的web服务器就完成了,可以用RESTClient测试一下。
  HTTPS相对于HTTP增加了SSL通道,客户端和服务器端必须有相互信任的证书才可以通信。自己对这方面的内容之前完全不了解,费了很大的功夫才初步把HTTPS的请求调通。
  相比于HTTP的服务器,HTTPS改动的地方主要是建立服务器的时候:
  class SecureHTTPServer(HTTPServer):
  def __init__(self, server_address, HandlerClass):
  BaseServer.__init__(self, server_address, HandlerClass)
  self.socket = ssl.SSLSocket(socket.socket(self.address_family,self.socket_type),keyfile='./server.key', certfile='./server.crt', server_side=True)
  self.server_bind()
  self.server_activate()
  这里新声明了一个SecureHTTPServer类,继承自HTTPServer类,在这个类中重新定义了构造函数,主要是新创建了一个SSLSocket类型的套接字,并指定了这个套接字的keyfile和certfile。keyfile和certfile这两个文件是安装了OpenSSL后手动生成的,执行如下openssl命令在本地生成pem文件:
req -new -x509 -keyout server.pem -out server.pem -day 365 -nodes
将server.pem文件中CERTIFICATE部分拷贝出来另存为server.crt。执行如下命令在本地生成或者删除证书:
keytool -import -alias certificatekey -file server.crt -keystore server.jks
keytool -delete -alias certificatekey -keystore server.jks
将server.jk上传到发送请求的系统作为证书库。
  
新声明一个handler类来处理收到的请求,并添加了多线程机制:
class SecureHTTPHandler(CGIHTTPRequestHandler):
#     def setup(self):
#         self.connection = self.request
# #         self.rbufsize = 8192   
# #         self.wbufsize = 8192
#         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
#         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
    def commonProcess(self):
        #处理请求的通用函数
        try:
      #设置不阻塞
            self.request.setblocking(0)
      #设置超时时间为5秒
            self.request.settimeout(5)
           #自己的处理代码
        f = open(curdir + sep + self.path)
            print self.path
            print 'This is a GET method!'
            self.send_response(200)
            self.send_header('Content-type',
                             'text/html')
            self.end_headers()
            self.wfile.write(f.read())
            f.close()        
        except:
            logging.error('Invalid request:%s!' % self.path)
            self.send_error(404,'Invalid request:%s!' % self.path)
            
    def do_GET(self):
        logging.info('Received url is %s' % self.path)
        logging.info('This is a GET method!')
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)
            
    def do_POST(self):
        logging.info('Received url is %s' % self.path)
        logging.info('This is a POST method!')
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)   
            
    def do_PUT(self):
        logging.info('Received url is %s' % self.path)
        logging.info('This is a PUT method!')
        #self.commonProcess()
        t = threading.Thread(target = self.commonProcess,args = ())
        t.start()
        t.join(5)
在main()函数中要声明这个类的对象来创建服务器:
    https_server = SecureHTTPServer(server_address,SecureHTTPHandler)
以下是客户端的测试代码:
import httplib
  def main():
  conn = httplib.HTTPSConnection(host = "127.0.0.1", port = 8443, key_file='./server.key', cert_file='./server.crt' , source_address = ('127.0.0.1',8080))
  print "requesting..."
  conn.request('PUT', '/test_body.txt')
  r1 = conn.getresponse()
  #打印响应码和响应状态信息
  print r1.status, r1.reason
另外,python中的twisted框架在处理web服务器时似乎功能很强大,后续可以深入研究一下。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-146112-1-1.html 上篇帖子: Python 学习小计 下篇帖子: Python:版本升级(Mac OS X)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表