美文网首页程序员
Python web服务器

Python web服务器

作者: PythonMaO | 来源:发表于2017-06-20 21:42 被阅读242次

Web静态服务器

显示静态的页面

import socket
import multiprocessing
import os,re
import time

G_PATH = './html'
def client(clientSocket,recvAddr):
    recvDate=clientSocket.recv(1024).decode('gbk')
    print(recvDate)
    a=recvDate.splitlines()[0]
    fileName=re.split(' +',a)[1]
    filePath = G_PATH
    if '/' == fileName:
        filePath += '/首页.html'      #默认首页
    else:
        filePath += fileName
    try:
        file = None
        file = open(filePath, 'r',encoding='gbk')
        responseBody = file.read()

        print(responseBody)
        responseLine = 'HTTP/1.1 200 OK'+os.linesep
        responseHeader = 'Server: laowang'+os.linesep+'Date: %s'%time.ctime() + os.linesep
    except FileNotFoundError:
        responseLine = 'HTTP/1.1 404 OK' + os.linesep
        responseHeader = 'Server: laowang' + os.linesep + 'Date: %s' % time.ctime() + os.linesep
        responseBody = '找不到'
    except Exception as ex:
        responseLine = 'HTTP/1.1 500 OK' + os.linesep
        responseHeader = 'Server: laowang' + os.linesep + 'Date: %s' % time.ctime() + os.linesep
        responseBody = '服务器正在升级中,请稍后再试。。。。。。%s'%ex
    finally:
        if (file != None) and (not file.closed):
            file.close()

    sendDate=(responseLine+responseHeader+os.linesep+responseBody).encode('gbk')
    clientSocket.send(sendDate)
    clientSocket.close()


def main():
    serveSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    serveSocket.bind(('',10086))
    serveSocket.listen()
    while True:
        clientSocket,clientAddr = serveSocket.accept()
        multiprocessing.Process(target=client,args=(clientSocket,clientAddr)).start()
        clientSocket.close()


if __name__ == '__main__':
    main()

首页.html

<html>
<title> 首页 </title>
<meta charset="utf-8">
<body> 这是<br>首页</body>
![](http://localhost:49249/课件/day30/html/girl.png)

</html>

客户端浏览器


Paste_Image.png

服务端


Paste_Image.png

Web服务器动态资源请求

浏览器请求动态页面过程

Paste_Image.png

WSGI

了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:

浏览器发送一个HTTP请求;

服务器收到请求,生成一个HTML文档;

服务器把HTML文档作为HTTP响应的Body发送给浏览器;

浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。

这个接口就是WSGI:Web Server Gateway Interface。

定义WSGI接口

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求我们来看一个最简单的Web版本的“Hello World!”:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return 'Hello World!'

上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

  • environ:一个包含所有HTTP请求信息的dict对象;
  • start_response:一个发送HTTP响应的函数。

application()函数中,调用:

start_response('200 OK', [('Content-Type', 'text/html')])

整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。

动态资源请求服务端代码

import socket, multiprocessing, re, time, os


class myServerModule:
    def __init__(self):
        serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serverSocket = serverSocket
        self.HTMLPATH = './html'

    def bind(self, port=10086):
        self.serverSocket.bind(('', port))

    def start(self):
        self.serverSocket.listen()
        while True:
            clientSocket, clientAddr = self.serverSocket.accept()
            multiprocessing.Process(target=self.clientHandler, args=(clientSocket, clientAddr)).start()
            clientSocket.close()

    def clientHandler(self, clientSocket, clientAddr):
        try:
            recvData = clientSocket.recv(1024).decode('gbk')
            print(recvData)
            fileName = re.split(r' +', recvData.splitlines()[0])[1]
            filePath = self.HTMLPATH
            if fileName.endswith('.py'):
                try:
                    pyName = fileName[1:-3]
                    print(pyName)
                    pyModule = __import__(pyName)
                    env = {}
                    responseBody = pyModule.application(env, self.startResponse)
                    responseLine = self.responseLine
                    responseHeader = self.responseHeader
                except ImportError as ex:
                    responseLine = 'HTTP/1.1 404 NOT FOUND' + os.linesep
                    responseHeader = 'Server: laowang' + os.linesep
                    responseHeader += 'Date: %s' % time.ctime() + os.linesep
                    responseBody = '<h1>找不到<h1>%s' % ex
            else:
                if '/' == fileName:
                    filePath += '/首页.html'
                else:
                    filePath += fileName

                try:
                    file = None
                    file = open(filePath, 'r', encoding='gbk')
                    responseBody = file.read() + filePath

                    responseLine = 'HTTP/1.1 200 OK' + os.linesep
                    responseHeader = 'Server: laowang' + os.linesep
                    responseHeader += 'Date: %s' % time.ctime() + os.linesep
                except FileNotFoundError as ex:
                    responseLine = 'HTTP/1.1 404 NOT FOUND' + os.linesep
                    responseHeader = 'Server: laowang' + os.linesep
                    responseHeader += 'Date: %s' % time.ctime() + os.linesep
                    responseBody = '<h1>找不到<h1>%s' % ex
                finally:
                    if (file != None) and (not file.closed):
                        file.close()
        except Exception:
            responseLine = 'HTTP/1.1 500 ERROR' + os.linesep
            responseHeader = 'Server: laowang' + os.linesep
            responseHeader += 'Date: %s' % time.ctime() + os.linesep
            responseBody = '服务器正在升级中,请稍后再试。。。。。。'
        finally:
            sendData = (responseLine + responseHeader + os.linesep + responseBody).encode('gbk')
            clientSocket.send(sendData)
            if (clientSocket != None) and (not clientSocket._closed):
                clientSocket.close()

    def startResponse(self, status, responseHeaders):
        self.responseLine = status
        self.responseHeader = ''
        for k, v in responseHeaders:
            kv = (k + ':' + v + os.linesep)
            self.responseHeader += kv


if __name__ == '__main__':
    server = myServerModule()
    server.bind(10086)
    server.start()

还有一个mytime.pypy模块

import time


def application(env, startResponse):
    status = 'HTTP/1.1 200 OK'
    responseHeaders = [('Server', 'laowang'), ('Date', '%s'%time.ctime()), ('Content-Type', 'text/plain')]
    startResponse(status, responseHeaders)
    responseBody = str(time.ctime())
    return responseBody

服务端

Paste_Image.png

客户端浏览器


Paste_Image.png

相关文章

网友评论

    本文标题:Python web服务器

    本文链接:https://www.haomeiwen.com/subject/etvaqxtx.html